5

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?

legends2k
  • 31,634
  • 25
  • 118
  • 222

4 Answers4

4

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
  • 95,107
  • 10
  • 109
  • 188
3

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
  • 30,981
  • 5
  • 61
  • 92
0

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
  • 3,168
  • 1
  • 21
  • 19
  • @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 Oct 11 '10 at 15:58
  • 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 Oct 13 '10 at 13:14
  • It seems preferable to return the number of bytes read as @CashCow explained with `istream::readsome`. As @Mark B explained, it avoids having to declare an extra int to pass by reference. Another option is passing a pointer to the variable that is defaulted to `NULL`, which can be used to ignore the actual number of bytes read: `istream& read(char* s, streamsize n, streamsize* bytesRead = NULL)`. However, I don't know if it will offer a significant advantage over `istream::readsome`. – Jaime Soto Oct 13 '10 at 13:42
0

In response to the original question, having error check calls was a popular programming style when C was young, but it went out of vogue soon after. What happens is little things that are not very wrong, but nevertheless are almost always just a little inferior exist for a while until they are called out and labeled as bad by the community. This code has the misfortune of having been written before that little anti-pattern was widely discussed.

In response to Cash Cow's solution, I think there is a bug. If you are waiting on IO and have enough chars to partially fill the buffer, then the function will return and the while loop will end before the file is completely read. So his solution would probably run correctly if written on top of straight raw IO, but would fail running over buffered IO.

The correct solution, of course, would be to end the while loop when the EOF flag is set. I am not sure at the moment what the best response is when badbit is set, but you should probably handle that case too.

I would agree that readsome is a decent alternative to read, though.

Edit: Sometimes readsome is not available (some VC++ versions). In this case, read is not unusable.

sf_jeff
  • 374
  • 2
  • 10