为什么在读取文件的最后一行后ifstream.eof()不返回TRUE?


11

当初学者开始阅读ifstreams时,他/她的本能是使用通常如下所示的循环来读取文件:

while (!ifstream.eof()
{
...
}

但是,当我使用此代码时,我注意到它直到读取了文件的最后一行两次才停止。C ++程序员注意到,这实际上并不是读取文件的方式。相反,他们通常建议需要读取文件的人使用这样的循环:

while (ifstream >> someVar)
{
...
}

为什么第一段代码总是无法正常工作?


我本以为会有重复的,但是我在这里找不到。stackoverflow上有很多重复项。
大卫·哈门

Answers:


4

while (!ifstream.eof())循环不工作,因为在C和C ++流/文件时,你已经达到了文件的末尾,但宁可表明,如果你已经尝试阅读不预测过去的文件的末尾。

如果文件的最后一行以换行符(\n)结束,则大多数读取操作将在遇到该字符时停止读取,并且他们不会检测到该碰巧是文件中的最后一个字符。在下一个读取动作中,甚至可能附加了更多字符,并且读取将成功提取它们。

使用流提取运算符(while (ifstream >> someVar))的循环之所以起作用,是因为如果无法提取正确类型的项,则流提取运算符的结果评估为false。如果没有字符可读取,也会发生这种情况。


4

但是,C ++程序员注意到,总是发生的情况是cin.eof()在读取了最后一行两次之后才返回“ true”。

那不是正在发生的事情。的eofbit播放没有在转换作用到布尔(stream::operator bool(或operator void*在旧的C ++))。仅涉及badbitfailbit

假设您正在读取一个文件,其中包含用空格分隔的数字。基于环的循环cin.eof()将不可避免地是错误的或充满了if测试。您要等到EOF才能阅读。您正在阅读数字。因此,使您的代码表达这种逻辑:

while (stream >> some_var) {
    process_value(some_var);
}

无论文件的最后一行以结尾0 42\n还是结尾0 42(文件最后一行的末尾没有新行),这都将起作用。如果文件以结尾0 42\n,则最后一次读取将检索值42,并读取行尾的最后一个标记。请注意,尚未读取EOF标记。该函数用process_value调用42。流中提取运算符>>下一次调用读取EOF,并且因为没有被提取,无论是eofbitfailbit将被设置。

另一方面,假设文件以0 42(结尾处没有换行符)结尾。最后一次良好读取将检索终止于EOF标记的值42。大概您要处理42。这就是为什么eofbit不会在输入流布尔转换运算符中起作用的原因。在下一次对流提取运算符>>的调用时,基础机器很快就会看到eofbit已设置。这很快导致设置failbit

为什么第一段代码总是无法正常工作?

因为您不应该将EOF作为循环条件进行检查。循环条件应表示您要执行的操作,例如,从流中提取数字。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.