#include <iostream>
#include <fstream>
int main() {
std::fstream inf( "ex.txt", std::ios::in );
while( !inf.eof() ) {
std::cout << inf.get() << "\n";
}
inf.close();
inf.clear();
inf.open( "ex.txt", std::ios::in );
char c;
while( inf >> c ) {
std::cout << c << "\n";
}
return 0;
}
I'm really confused about eof()
function. Suppose that my ex.txt's content was:
abc
It always reads an extra character and shows -1
when reading using eof()
. But the inf >> c
gave the correct output which was 'abc'? Can anyone help me explain this?
-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.
The EOF flag is only set after a read operation attempts to read past the end of the file. get()
is returning the symbolic constant traits::eof()
(which just happens to equal -1) because it reached the end of the file and could not read any more data, and only at that point will eof()
be true. If you want to check for this condition, you can do something like the following:
int ch;
while ((ch = inf.get()) != EOF) {
std::cout << static_cast<char>(ch) << "\n";
}
iostream doesn't know it's at the end of the file until it tries to read that first character past the end of the file.
The sample code at cplusplus.com says to do it like this: (But you shouldn't actually do it this way)
while (is.good()) // loop while extraction from file is possible
{
c = is.get(); // get character from file
if (is.good())
cout << c;
}
A better idiom is to move the read into the loop condition, like so:
(You can do this with all istream
read operations that return *this
, including the >>
operator)
char c;
while(is.get(c))
cout << c;
eof() checks the eofbit in the stream state.
On each read operation, if the position is at the end of stream and more data has to be read, eofbit is set to true. Therefore you're going to get an extra character before you get eofbit=1.
The correct way is to check whether the eof was reached (or, whether the read operation succeeded) after the reading operation. This is what your second version does - you do a read operation, and then use the resulting stream object reference (which >> returns) as a boolean value, which results in check for fail().
来源:https://stackoverflow.com/questions/4533063/how-does-ifstreams-eof-work