views:

82

answers:

3

std::istream has the prototype istream& read (char* s, streamsize n) the actual number of bytes read should be gotten by calling istream::gcount(), also the validity of the istream can be known from ios::good.

I was discussing another stream class' implementation I was trying to write with a colleague of mine, where I was saying I might follow this design; but he said instead of having the user call gcount everytime, one could have read's prototype like this istream& read (char* s, streamsize n, size_t &bytes_read) so that it'll get over in a single call and the former is clumsier. I was unable to defend std's design choice. What's the real rationale behind istream::read?

+1  A: 

I assume it's because C++ doesn't typically force an interface that may not be needed by everyone. If you require read to accept a parameter that some people don't care about, then it causes extra coding work (declaring an extra int to pass as a parameter). It also always saves the bytes read regardless of whether the client cares or not (some clients may just care that the read failed as indicated by the eof/fail bits).

With a separate method you de-couple the interface for different pieces of information that may or may not be needed.

Mark B
A: 

std::istream has the prototype istream& read (char* s, streamsize n) the actual number of bytes read should be gotten by calling istream::gcount(), also the validity of the istream can be known from ios::good.

istream::read(char* s, streamsize n) reads an unformatted block of data (without NULL termination) of size n into the array at s. Even though s is a pointer to char, you can use istream::read to read binary data. For example, you could have an istream that holds the values of an array of doubles (assuming that the endianness is correct):

unsigned int count;
input.read(reinterpret_cast<char*>(&count), sizeof(count));
double* data = new double[count];

for (unsigned int i = 0; i < count; ++i)
    input.read(reinterpret_cast<char*>(data[i]), sizeof(double));

istream::gcount() returns the number of bytes read in the last istream::read call. In this case, we see that the size of count is probably different from the size of a double, therefore we would not be able to use istream::gcount() to specify the size of the first element in the data array.

Jaime Soto
@CashCow Has the correct solution to the limitations of `istream::read`. I can't upvote because I don't have at least 15 points of reputation (I'm still a Stack Overflow n00b).
Jaime Soto
My actual question was, why do we need to call `gcount`; instead why no have it like the caller can pass a refernce variable, which will be set by `read` to the number of bytes actually read (which can be less than or equal to `streamsize n`), instead of the caller calling gcount everytime.
legends2k
Jaime Soto
+1  A: 

Try the readsome command instead,

streamsize readsome ( char* buf, streamsize num );

buf is your buffer and num is the number of bytes you wish to read, at most the number of bytes available in your buffer, of course.

The return value is the number of bytes actually read.

To read a file to the end you can loop:

char buf[BUF_SIZE]
streamsize bytesRead;
do
{
   bytesRead = instr.readsome( buf, BUF_SIZE );
   // do stuff with the bytes you read, if any
} while ( bytesRead == BUF_SIZE );
CashCow