2014-12-03 82 views
1

我在理解C++中的文件输入流时感到很挣扎。我有一个代码片段如下:ifstream.eof()在C++中没有评估为true

#include <iostream> 
#include <fstream> 
#include <string> 

using namespace std; 

int main() { 
    ifstream in("x.txt"); 

    bool done = false; 
    do { 
     string input = ""; 
     getline(in,input); 
     int x1; 
     int x2; 
     in >> x1; 
     in >> x2; 
     cout << input << " " << x1 << " " << x2 << endl; 
     in.ignore(); 
     if(in.eof()) { 
      done = true; 
      cout << "reached eof" << endl; 
     } 
    } while(!done); 

    return 0; 
} 

随着文件x.txt阅读如下

task1 
12 
1313 
task2 
13 
1414 
[blank line] 

注意在输入文件的末尾故意包含空行的。所有这一切意味着输入“1414”后按下了输入/返回键。

我的预期输出是

task1 12 1313 
task2 13 1414 
reached eof 

但实际上,输出

task1 12 1313 
task2 13 1414 
13 1414 
reached eof 

我明白,按enter内的输入文件生成一个隐换行符,并使用像一个语句之前getline(ifstream, string)我们应该ignore()那下一个换行符。这就是说,为什么ifstream.eof()没有评估为真,即使在'1414'之后的隐含换行符是ignore()

+3

'而(在X1 >> >> X2)' – Borgleader 2014-12-03 15:31:33

+1

你为什么不测试的返回值'getline'? 'in >> x1'和'in >> x2'同样的问题?如果您有问题,我/ O **检查I/O工作** – 2014-12-03 15:32:29

+0

这基本上是http://stackoverflow.com/q/5605125/981959具有不同(但仍然是错误的)环 – 2014-12-03 15:34:45

回答

2

eof标志在您尝试读取超出文件末尾之前未设置。而应该检查结果从流中读取,或许像

while (getline(in, input) && in >> x1 >> x2) { 
    cout << input << " " << x1 << " " << x2 << endl; 
    in.ignore(); 
} 
cout << "reached eof" << endl; 
+0

重复他也许应该忽略,直到''\ n''为好,以防万一出现在该行的末尾多余的空白。 – 2014-12-03 15:52:10

0

在第二循环流的位置是在年底结束后,但不会设置eofbit,直到您尝试读取更多的数据。让我们考虑前两个循环已经运行后会发生什么,你进入第三次循环:

您尝试读取一行:

getline(in,input); 

该读什么,因为你已经到达了流的末尾,所以它设置eofbit,因为没有提取也设置failbit。但是你不检查一个线被读取,或者如果input非空,你只是盲目地继续

你声明了两个未初始化的变量:

int x1; 
    int x2; 

然后再次尝试阅读:

in >> x1; 
    in >> x2; 

这甚至不尝试读取任何东西,因为failbit已经设置,但你不要在这里检查它。 x1x2保持不变并保持未初始化。

然后你打印出来的未初始化的整数,这恰好从以前循环打印出来的值,因为这就是恰好是在栈上:

cout << input << " " << x1 << " " << x2 << endl; 

这什么也不做,因为failbit设置:

in.ignore(); 

现在最后您检查流状态,但它来得太迟,以防止上面的所有问题:

if(in.eof()) { 

您应该检查I/O操作是否成功,而不是假设他们这样做,然后在很晚的时候发现他们有什么问题,但是现在为时已晚。

检查I/O操作的方法是在布尔上下文中测试流, if (in),你应该是检查EOF因为不被设置,直到你到达流的末尾,然后尝试读取再次

小李的回答显示了正确的方式做到这一点,但你也应该阅读Why is iostream::eof inside a loop condition considered wrong?

+0

如果他已经提取的文件的最后一个字符(与'ignore'),那么'eofbit'和'failbit'应该在'getline'进行设置,在'在>> x1'之前达到。 – 2014-12-03 15:54:22

+0

@JamesKanze,嗯,是的,我错误地忽略了忽略:)我确实提到过,当'failbit'设置时它甚至不会尝试做任何事情,我会更清楚地说明 – 2014-12-03 15:55:20