简体   繁体   中英

Custom buffered input stream. End of input

The problem is the following: I'm writing a custom buffered input stream that reads strings in chunks of specific size that should be transformed (various ways: changed symbols, whole chunks skipped if specific content is found etc.). Transformation itself is irrelevant atm, because I'm stuck at understanding input in general. Here is the code (based from https://stackoverflow.com/a/14086442/3651664 ):

#include <fstream>
#include <iostream>
#include <cstring>

class skipchar_stream_buffer: public std::streambuf
{
private:
  char* m_buffer;
  std::streambuf* m_stream_buffer;
  std::streamsize m_size;
public:
  skipchar_stream_buffer(std::streambuf* stream_buffer);
  virtual ~skipchar_stream_buffer();
  virtual std::streambuf::int_type underflow();
};

skipchar_stream_buffer::skipchar_stream_buffer(std::streambuf* stream_buffer)
{
  m_size = 10;
  m_buffer = new char[m_size]();
  m_stream_buffer = stream_buffer;
}

skipchar_stream_buffer::~skipchar_stream_buffer()
{
  delete[] m_buffer;
}

std::streambuf::int_type skipchar_stream_buffer::underflow()
{
  std::memset(m_buffer, 0, m_size);

  std::streamsize read = m_stream_buffer->sgetn(m_buffer, m_size);

  setg(m_buffer, m_buffer, m_buffer + m_size);

  std::cout << "buffer = '" << m_buffer << "'" << std::endl;

  if (gptr() == egptr())
    return traits_type::eof();
  else
    return traits_type::to_int_type(*gptr());
}

class skipchar_istream: public std::istream
{
public:
  skipchar_istream(std::istream& stream);
  virtual ~skipchar_istream();
};

skipchar_istream::skipchar_istream(std::istream& stream) :
  std::istream(new skipchar_stream_buffer(stream.rdbuf()))
{

}

skipchar_istream::~skipchar_istream()
{
  delete rdbuf();
}

int main()
{
  char s[32];

  skipchar_istream in(std::cin);
  in >> s;
  std::cout << s;

  return 0;
}

And the question is: why do I need to explicitly finish input (by sending EOF for example)? Why is pressing enter not enough? Or am I doing this completely wrong at all? Working in VS2010.


Update: Found another problem with this code: if supplied character count is not a multiple of buffer size, underflow method is not called automatically (only once at first). Why is that? Is smth wrong with pointer settings in setg ?

Pressing Enter sends character to the i/o buffer. That doesn't mean 'end of input'. In your file you can easily have something like

Dear Mr. Smith,<CR><EOL>I am writing to you this message.<CR><EOL>Kind regards,<CR><EOL>Your Name<EOF>

The standard stream gives you a lot of flexibility in how to read this input.

For example:

istream get() will return you 'D'
istream operator >> will return "Dear"
istream getline () will return "Dear Mr. Smith,"
streambuf sgetn (6) will return "Dear M"

You can also adjust their behaviour to your needs. So you can read as much or as little as you want.

In your code the reading operation is:

std::streamsize read = m_stream_buffer->sgetn(m_buffer, m_size);

which means "give me m_size characters or less if end of input occurred". Have a look at the documentation of streambuf for a better explanation. http://www.cplusplus.com/reference/streambuf/streambuf

std::streambuf works on per character basis. No getline() or operator>> here. If you want to stop at a particular character (eg ) you will probably need a loop with sgetc().

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM