124

以下C++代码使用ifstream对象从文本文件(每行有一个数字)中读取整数,直到到达EOF为止。为什么它读取最后一行的整数两次?如何解决这个问题?

代码:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    ifstream iFile("input.txt");    // input.txt has integers, one per line

    while (!iFile.eof())
    {
        int x;
        iFile >> x;
        cerr << x << endl;
    }

    return 0;
}

输入.txt

10  
20  
30

输出

10  
20  
30  
30

注意:我已跳过所有错误检查代码以保持代码片段较小。在 Windows (Visual C++)、cygwin (gcc) 和 Linux (gcc) 上可以看到上述行为。

4

7 回答 7

132

只需密切关注事件链。

  • 抢10
  • 抢 20
  • 抢 30
  • 抓取EOF

查看倒数第二次迭代。你抓住了 30,然后继续检查 EOF。您尚未达到 EOF,因为尚未读取 EOF 标记(“二进制”而言,它的概念位置就在 30 行之后)。因此,您继续进行下一次迭代。x 仍然是前一次迭代的 30。现在您从流中读取并获得 EOF。x 保持 30 并且 ios::eofbit 被提升。你输出到 stderr x (这是 30,就像在之前的迭代中一样)。接下来,您检查循环条件中的 EOF,这一次您退出了循环。

试试这个:

while (true) {
    int x;
    iFile >> x;
    if( iFile.eof() ) break;
    cerr << x << endl;
}

顺便说一句,您的代码中还有另一个错误。你有没有试过在一个空文件上运行它?你得到的行为是出于完全相同的原因。

于 2008-08-22T02:50:56.403 回答
38

我喜欢这个例子,它现在省略了你可以在 while 块中添加的检查:

ifstream iFile("input.txt");        // input.txt has integers, one per line
int x;

while (iFile >> x) 
{
    cerr << x << endl;
}

不知道它有多安全......

于 2008-08-22T02:59:25.477 回答
15

有一种替代方法:

#include <iterator>
#include <algorithm>

// ...

    copy(istream_iterator<int>(iFile), istream_iterator<int>(),
         ostream_iterator<int>(cerr, "\n"));
于 2008-08-22T04:46:33.503 回答
6

无需对原始代码进行太多修改,它可能会变成:

while (!iFile.eof())
{  
    int x;
    iFile >> x;
    if (!iFile.eof()) break;
    cerr << x << endl;
}

但总的来说,我更喜欢上面的其他两种解决方案。

于 2013-02-12T16:17:56.190 回答
5

EOF 模式需要一个主要读取来“引导”EOF 检查过程。考虑到空文件最初不会在第一次读取之前设置其 EOF。在这种情况下,主要读取将捕获 EOF 并正确地完全跳过循环。

您需要记住的是,在第一次尝试读取文件的可用数据之前,您不会获得 EOF。读取确切的数据量不会标记 EOF。

我应该指出,如果文件为空,您的给定代码将被打印,因为 EOF 将阻止在进入循环时将值设置为 x。

  • 0

所以添加一个素数读取并将循环的读取移动到末尾:

int x;

iFile >> x; // prime read here
while (!iFile.eof()) {
    cerr << x << endl;
    iFile >> x;
}
于 2014-12-03T13:56:26.360 回答
2
int x;
ifile >> x

while (!iFile.eof())
{  
    cerr << x << endl;        
    iFile >> x;      
}
于 2013-04-11T20:29:34.080 回答
2

在最后一行的末尾,您有一个换行符,>> 运算符不会读取该换行符,并且它不是文件结尾。请做一个实验并删除新行(文件中的最后一个字符) - 你不会得到重复。要拥有灵活的代码并避免不必要的影响,只需应用其他用户提供的任何解决方案。

于 2014-12-20T22:53:39.747 回答