ifstream的eof()如何工作?

#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; } 

我真的很困惑eof()函数。 假设我的ex.txt的内容是:

 abc 

它总是读取一个额外的字符,并使用eof()读取时显示-1 。 但inf >> c给出了正确的输出是'abc'? 任何人都可以帮我解释一下吗?

-1就是说你已经到达文件的末尾了。 比较它使用std::char_traits<char>::eof() (或std::istream::traits_type::eof() ) – 避免-1,这是一个幻数。 (尽pipe另一个有点冗长 – 你总是可以调用istream::eof

EOF标志只有在读取试图读取文件末尾时才被设置。 如果我有一个3字节的文件,而我只读了3个字节,EOF是false ,因为我还没有尝试读过文件的末尾。 虽然这对于通常知道它们的大小的文件来说似乎很困惑,但是直到在一些设备(例如pipe道和networking套接字)上尝试读取之后才知道EOF。

第二个例子的工作原理是: inf >> foo将总是返回inf ,带有尝试读取并将其存储在foo的副作用。 inf ,在ifwhile ,如果文件是“好的”,则评估为true :没有错误,没有EOF。 因此,当读取失败时, inf会变成false ,并且你的循环正确地中止。 但是,采取这个常见的错误:

 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. } 

但是,这个:

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

这是我们想要的。

iostream不知道它在文件的末尾,直到它试图读取文件末尾的第一个字符。

在cplusplus.com的示例代码说这样做:(但是你不应该这样做)

  while (is.good()) // loop while extraction from file is possible { c = is.get(); // get character from file if (is.good()) cout << c; } 

更好的习惯是将读取操作移动到循环条件中,如下所示:(您可以使用所有返回*this istream读取操作(包括>>操作符)

  char c; while(is.get(c)) cout << c; 

EOF标志只在读取操作尝试读取文件结尾之后才被设置。 get()返回符号常量traits::eof() (它恰好等于-1),因为它到达了文件的末尾,并且不能再读取任何数据,只有在那时eof()为真。 如果你想检查这种情况,你可以做如下的事情:

 int ch; while ((ch = inf.get()) != EOF) { std::cout << static_cast<char>(ch) << "\n"; } 

eof()检查stream状态下的eofbit。

在每个读取操作中,如果位置在stream的末尾并且需要读取更多数据,则eofbit设置为true。 因此,在获得eofbit = 1之前,你会得到一个额外的字符。

正确的方法是在读操作检查eof是否到达(或读操作是否成功)。 这是你的第二个版本 – 你做一个读取操作,然后使用生成的stream对象引用(这将返回)作为布尔值,这导致检查fail()。