ifstream.eof()在C ++中没有评估为true

时间:2014-12-03 15:30:02

标签: c++ file input ifstream eof

我正在努力理解C ++中的文件输入流。我有一个代码片段如下:

#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()下一个换行符。话虽如此,为什么即使I ignore()'1414'之后的隐式换行符,ifstream.eof()也没有评估为真?

2 个答案:

答案 0 :(得分:2)

在尝试超出文件末尾读取之前,eof标志不会设置。您应该在从流中读取后检查结果,可能类似

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

答案 1 :(得分: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?