How Does Ifstream'S Eof() Work

How does ifstream's eof() work?

-1 is get's way of saying you've reached the end of file. Compare it using the std::char_traits<char>::eof() (or std::istream::traits_type::eof()) - avoid -1, it's a magic number. (Although the other one is a bit verbose - you can always just call istream::eof)

The EOF flag is only set once a read tries to read past the end of the file. If I have a 3 byte file, and I only read 3 bytes, EOF is false, because I've not tried to read past the end of the file yet. While this seems confusing for files, which typically know their size, EOF is not known until a read is attempted on some devices, such as pipes and network sockets.

The second example works as inf >> foo will always return inf, with the side effect of attempt to read something and store it in foo. inf, in an if or while, will evaluate to true if the file is "good": no errors, no EOF. Thus, when a read fails, inf evaulates to false, and your loop properly aborts. However, take this common error:

while(!inf.eof())  // EOF is false here
{
inf >> x; // read fails, EOF becomes true, x is not set
// use x // we use x, despite our read failing.
}

However, this:

while(inf >> x)  // Attempt read into x, return false if it fails
{
// will only be entered if read succeeded.
}

Which is what we want.

Why does std::fstream set the EOF bit the way it does?

Because this way it can detect EOF without knowing how large the file is. All it has to do is simply attempt to read and if the read is short (but not an error), then you have reached the end of the file.

This mirrors the functionality of the read system call, which file IO typically ends up calling (win32 stuff may call ReadFile but I believe that the functionality is similar).

From the read manpage "RETURN VALUE" section (emphasis added):

On success, the number of bytes read
is returned (zero indicates end of
file)
, and the file position is
advanced by this number. It is not an
error if this number is smaller than
the number of bytes requested; this
may happen for example because fewer
bytes are actually available right now
(maybe because we were close to
end-of-file, or because we are reading
from a pipe, or from a terminal), or
because read() was interrupted by a
signal. On error, -1 is returned, and
errno is set appropriately. In this
case it is left unspecified whether
the file position (if any) changes.

BTW: a good way to write what you wanted would be like this:

T something;
while(file.read(something, sizeof(something))) {
// process your 'something'
}

this works because file.read (like many members of iostream) return a reference to the iostream itself. All of which have an operator overloaded to allow testing the stream state. Similarly to read from std::cin, while(std::cin >> x) { ... } works as well.

EDIT: you should know that testing vs. fail can be equally wrong for the same reason. From the page you linked to fail() returns if the previous operation failed. Which means you need to perform a read or other relevant operation before testing it.

why does eof() not work as I expect?

The problem is that when extracting symbols for 45,it tries to extract symbol after '5' (to check if number continues further) and sees end of file, setting eofbit. This makes in.good() test to fail. Suggestions:

while (!in.eof()){
in >> i;
if ( in ) { //Not .good(), just conversion to bool

Or

while (!in.eof()){
if ( in >> i; ) { //both extraction and checking in same operation

Remember, .good() is not the same as checking stream state. .good() is telling if stream ready for further input. Bool conversion does ! .fail() and checks if last operation was executed succesfully

Ifstream hitting eof early

std::ifstream file(filename, std::ios::in || std::ios::binary);

you're using the logical || operator in place of the bitwise | operator in the stream flag parameter. If the bitmask turns out to be implemented as an integer or plain enum type, no error will occur and the resulting flag will be converted to 1 ( whatever such a flag value is supposed to mean on your implementation ).

Difference between while(!file.eof()) and while(file >> variable)

The difference is that >> reads the data first, and then tells you whether it has been a success or not, while file.eof() does the check prior to the reading. That is why you get an extra read with the file.eof() approach, and that read is invalid.

You can modify the file.eof() code to make it work by moving the check to a place after the read, like this:

// This code has a problem, too!
while (true) { // We do not know if it's EOF until we try to read
file >> BinaryNumber; // Try reading first
if (file.eof()) { // Now it's OK to check for EOF
break; // We're at the end of file - exit the loop
}
sum+=decimal(BinaryNumber);
}

However, this code would break if there is no delimiter following the last data entry. So your second approach (i.e. checking the result of >>) is the correct one.

EDIT: This post was edited in response to this comment.

ifstream EOF executing early

It looks like you discard the data at the end of the file if the file size isn't an exact multiple of SIZE.

Also, even if the file size is an exact multiple of SIZE you'll be reading the last character and then eof() will not return true. Not until you've tried reading the next character will eof() return true, and that will trigger your error message, ERROR: EOF DETECTED.

More on that here:

Why is iostream::eof() inside a loop condition (i.e. while (!stream.eof())) considered wrong?

An alternative approach:

unsigned i = 0;

while(my_file >> file_buffer[i]) { // loop for as long as extracting succeeds
if(++i == SIZE) {
sendData(client_socket, file_buffer, i); // add a size parameter
// memset(file_buffer, 0, sizeof file_buffer); // why waste the time?
i = 0;
}
}

if(i) sendData(client_socket, file_buffer, i); // send the last part in the buffer


Related Topics



Leave a reply



Submit