测试 stream.good() 或 !stream.eof() 读取最后一行两次 [duplicate]

Testing stream.good() or !stream.eof() reads last line twice [duplicate]

提问人:Prabhu 提问时间:12/1/2010 最后编辑:CommunityPrabhu 更新时间:2/27/2013 访问量:31320

问:

这个问题在这里已经有答案了:
12年前关闭。

可能的重复为什么循环条件中的 iostream::
eof 被认为是错误的?

我有以下一段代码:

ifstream f("x.txt");
string line;
while (f.good()) {
  getline(f, line);
  // Use line here.
}

但这会读最后一行两次。为什么会发生这种情况,我该如何解决?

非常相似的情况发生:

ifstream f("x.txt");
string line;
while (!f.eof()) {
  getline(f, line);
  // Use line here.
}
C++ IOstream

评论

4赞 Jerry Jeremiah 5/16/2014
这怎么是重复的?另一个答案甚至没有提到使用 good() 函数作为测试进行循环。
1赞 melpomene 5/4/2019
@JerryJeremiah 尝试检查当前流状态(例如,,)以预测未来读取操作(例如,)的成功与此的一般问题相同。这不起作用,因为流状态告诉您之前的读取操作是否失败/到达输入末尾;它不会告诉您有关未来读取尝试的任何信息。.good().eof().fail()getline>>

答:

9赞 Fred Foo 12/1/2010 #1

只需使用

ifstream f("x.txt");
while (getline(f, line)) {
    // whatever
}

这是编写此类循环的惯用方式。我无法重现该错误(在 Linux 机器上)。

评论

0赞 Aaron McDaid 5/20/2011
我刚刚意识到为什么会这样:如果最后一行末尾没有换行符,那么最后一次成功调用 getline() 可能会设置 eof。仅当对 getline() 的调用不成功时,才会设置失败位。因此,我们不想eof 结束循环,但我们确实希望在失败时结束它。
0赞 Aaron McDaid 5/20/2011
还有一件事..我一直在做.我认为这是正确的吗?但我以后会用你的答案。while(f.peek() != EOF) { ... }
3赞 CashCow 12/1/2010 #2

它没有读取最后一行两次,但由于它在到达 eof 时无法读取,因此您的字符串行具有之前的值。

这是因为 f 在读取 EOF 时不再是“好”的,而不是在将要读取它时。

34赞 Fred Nurk 12/1/2010 #3

你很少想检查坏的、eof的和好的。特别是对于 eof(因为 !stream.eof() 是一个常见的错误),当前处于 EOF 的流并不一定意味着最后一个输入操作失败;相反,不在EOF并不意味着最后一个输入是成功的。

所有流状态函数(失败、坏、EOF 和良好)都会告诉您流的当前状态,而不是预测未来操作的成功。在所需操作后检查流本身(相当于反向失败检查):

if (getline(stream, line)) {
  use(line);
}
else {
  handle_error();
}

if (stream >> foo >> bar) {
  use(foo, bar);
}
else {
  handle_error();
}

if (!(stream >> foo)) {  // operator! is overloaded for streams
  throw SomeException();
}
use(foo);

要读取和处理所有行:

for (std::string line; getline(stream, line);) {
  process(line);
}

值得一提的是,good() 被错误地命名了,并不等同于测试流本身(上面的例子就是这样做的)。

评论

0赞 KeithB 12/1/2010
关于检查 eof 的部分是正确的,但检查流本身的建议有点偏离。 表示未设置 EOFBIT、Badbit 或 FAILBIT。 表示设置了 Badbit 或 Failbit。检查流(使用 void* 转换或运算符 !)与调用 fail() 成员函数完全相同。good()fail()
2赞 Fred Nurk 12/1/2010
@KeithB:你可能会注意到,我把失败排除在“应该很少检查”的组之外。失败的流很重要,检查流本身几乎总是比等效的 fail() 更方便。将 getline(stream, line) 与 !getline(stream, line).fail() 进行比较。