以下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;
}


input.txt:

10  
20  
30


输出:

10  
20  
30  
30


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

#1 楼

只需密切关注事件链。


抓斗10
抓斗20
抓斗30
抓斗EOF

看看倒数第二次迭代。您抢了30个,然后继续检查EOF。您尚未到达EOF,因为尚未读取EOF标记(“按二进制”来讲,其概念位置在30行之后)。因此,您继续进行下一个迭代。 x仍然是前一次迭代的30。现在,您从流中读取并获得EOF。 x仍然为30,并且ios :: eofbit被引发。您输出到stderr x(这是30,就像在上一次迭代中一样)。接下来,您要在循环条件下检查EOF,这一次您就脱离了循环。

请尝试以下操作:顺便说一句,您的代码中还有另一个错误。您是否曾经尝试在空文件上运行它?您得到的行为是完全相同的原因。

评论


使用'while(iFile >> x)'。这将读取整数并返回流。当流用作布尔值时,它将检查该流是否有效。有效表示eof()和bad()均为false。参见stackoverflow.com/questions/21647/…

–马丁·约克
08-09-23在7:48

与up注释具有相同的精神:代替while(true),写while(file.good())似乎更好

– PHF
2012年4月13日在15:14

如果您不确定在错误或文件结束之前如何读取文件,请阅读此文章(很好的解释)gehrcke.de/2011/06/…

–stviper
2015年10月8日在6:49

#2 楼

我喜欢这个示例,目前为止,该示例省去了可以在while块中添加的检查内容:

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

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


不确定它的安全性...

评论


如果0是有效值,例如x == 0,该怎么办?

–harryngh
14年7月4日在11:21

@harryngh如果我正确理解,iFile >> x将返回流本身,而不是x。然后,将流隐式转换为bool,以测试EOF。

– wchargin
2015年5月2日,3:22

#3 楼

还有另一种方法:

#include <iterator>
#include <algorithm>

// ...

    copy(istream_iterator<int>(iFile), istream_iterator<int>(),
         ostream_iterator<int>(cerr, "\n"));


#4 楼

如果不对原始代码进行大量修改,它可能会变成:

评论


我想这应该是(iFile.eof())中断了吗?没有!

–范思哲(Bouke Versteegh)
9月23日晚上9:27

#5 楼

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

我应该指出文件是否为空,否则将打印给定的代码,因为EOF会阻止在输入时将值设置为x


0

因此添加主读并将循环的读移至末尾:

int x;

iFile >> x; // prime read here
while (!iFile.eof()) {
    cerr << x << endl;
    iFile >> x;
}


#6 楼

int x;
ifile >> x

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


#7 楼

在最后一行的末尾,您有一个换行符,>>运算符不会读取它,也不是文件的末尾。
请进行实验并删除新行(换行符为文件)-您将不会得到重复。
要使用灵活的代码并避免产生不良影响,只需应用其他用户提供的任何解决方案即可。