9

If I wanted to read() the content of a std::istream in to a buffer, I would have to find out how much data was available first to know how big to make the buffer. And to get the number of available bytes from an istream, I am currently doing something like this:

std::streamsize available( std::istream &is )
{
    std::streampos pos = is.tellg();
    is.seekg( 0, std::ios::end );
    std::streamsize len = is.tellg() - pos;
    is.seekg( pos );
    return len;
}

And similarly, since std::istream::eof() isn't a very useful fundtion AFAICT, to find out if the istream's get pointer is at the end of the stream, I'm doing this:

bool at_eof( std::istream &is )
{
    return available( is ) == 0;
}

My question:

Is there a better way of getting the number of available bytes from an istream? If not in the standard library, in boost, perhaps?

edam
  • 718
  • 1
  • 8
  • 13
  • 5
    *I would have to find out how much data was available first to know how big to make the buffer* - not true. See [this answer of mine](http://stackoverflow.com/questions/5420317/c-reading-and-writing-binary-file/5420568#5420568) (second part). – Björn Pollex Jul 12 '11 at 15:44
  • Wow, interesting answer. I think this will work. Thankyou! – edam Jul 12 '11 at 15:54
  • @edam: Why do you need to know the buffer size in advance, can you not read as much as the buffer you have? – Alok Save Jul 12 '11 at 15:54
  • @Als: I need to allocate a buffer, fill it with data from the `istream` and pass it to a library with a C-style API. So, ultimately, I need a pointer to the data and the length of the data. – edam Jul 12 '11 at 16:03
  • @edam: If you need to read all the data in one go, then @Space_C0wb0y, answer in the link does just that, else you can always read data by the size you allocate and then use it further on, Anyhow the solution suggested seems better. – Alok Save Jul 12 '11 at 16:07
  • @Als: yes, @Space_C0wb0y, you should post your suggestion as an answer! – edam Jul 12 '11 at 16:16
  • 1
    You might want to look through my [answer](http://stackoverflow.com/questions/3303527/how-to-pre-allocate-memory-for-a-stdstring-object/3304059#3304059) to a previous question. The bottom line is that while @Space_C0wb0y's answer seems like it should be a good one, there are alternatives that are generally better -- almost regardless of what tradeoff between speed and elegance you prefer (in particular, the `sstream << stream.rdbuf();` elegant *and* quite fast, though not the fastest). – Jerry Coffin Jul 12 '11 at 17:12

2 Answers2

4

For std::cin you don't need to worry about buffering because it is buffered already --- and you can't predict how many keys the user strokes.

For opened binary std::ifstream, which are also buffered, you can call the seekg(0, std::ios:end) and tellg() methods to determine, how many bytes are there.

You can also call the gcount() method after reading:

char buffer[SIZE];

while (in.read(buffer,SIZE))
{
  std::streamsize num = in.gcount();
  // call your API with num bytes in buffer 
}

For text input reading via std::getline(inputstream, a_string) and analyzing that string afterwards can be useful.

René Richter
  • 3,512
  • 2
  • 27
  • 37
3

Posting this as an answer, as it seems to be what the OP wants.

I would have to find out how much data was available first to know how big to make the buffer - not true. See this answer of mine (second part).

Community
  • 1
  • 1
Björn Pollex
  • 70,106
  • 28
  • 177
  • 265
  • This doesn't seem to work quite right... Using `istream_iterator< char >` skips spaces on the `istream`, even when you use it with `copy()`. So the `vector< char>` buffer that you end up with has all spaces removed! – edam Jul 13 '11 at 09:18