ifstream的eof()如何工作?

Cha*_*han 40 c++ 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;
}
Run Code Online (Sandbox Code Playgroud)

我真的很困惑eof()功能.假设我的ex.txt的内容是:

abc
Run Code Online (Sandbox Code Playgroud)

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

Tha*_*tos 69

-1是get说你到达文件末尾的方式.使用std::char_traits<char>::eof()(或std::istream::traits_type::eof())比较- 避免-1,这是一个神奇的数字.(虽然另一个有点冗长 - 你总是可以打电话istream::eof)

EOF标志仅在读取尝试读取超过文件末尾时设置.如果我有一个3字节的文件,而我只读取3个字节,那么EOF就是false,因为我还没有尝试读过文件的末尾.虽然这对于通常知道其大小的文件而言似乎令人困惑,但在某些设备(例如管道和网络套接字)上尝试读取之前,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.
}
Run Code Online (Sandbox Code Playgroud)

但是,这个:

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

这就是我们想要的.

  • 可能不应该使用>>而不是get().请记住,>>运算符总是在尝试读取下一个值之前跳过前进的空格,而get()一次读取每个字符. (3认同)

Jus*_*ers 7

EOF标志仅在读取操作尝试读取超过文件末尾后设置.get()返回符号常量traits::eof()(恰好等于-1),因为它到达文件的末尾并且无法读取更多数据,并且只有在那一点才会eof()成立.如果要检查此条件,可以执行以下操作:

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

  • "只有在读取操作到达文件末尾后才会设置EOF标志." 正是引起EOF混淆的陈述.EOF标志仅在读取操作尝试读取超过文件末尾*后设置*.最后一位非常重要:如果我从一个3字节长的文件中读取3个字节,则EOF为false,直到我尝试另一次读取. (5认同)

Ken*_*oom 7

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;
  }
Run Code Online (Sandbox Code Playgroud)

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

  char c;
  while(is.get(c))
    cout << c;
Run Code Online (Sandbox Code Playgroud)

  • 你想要`!is.fail()`而不是`is.good()`.当从文件中读取例如数字时,流必须到达文件的末尾,然后确定它是否读取该数字的最后一位数.在这种情况下,一个数字将被成功读取,但将到达文件的末尾,导致`is.good()`返回false.这可能会导致您跳过文件的最后一个值.相反,检查`!is.fail()`会在所有情况下做正确的事情. (2认同)
  • @smgreenfield:采用输出参数的 get 重载返回 istream&amp; 以进行进一步链接或错误报告。 (2认同)