我正在努力理解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()也没有评估为真?
答案 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
已经设置好,但您也不会在这里查看。 x1
和x2
保持不变,并保持未初始化状态。
然后你打印出未初始化的整数,这恰好打印出来自之前循环的值,因为它会发生在堆栈上:
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?