我给出了一个答案,我希望每次通过循环here检查流的有效性。
我的原始代码使用了good
,看起来与此相似:
ifstream foo("foo.txt");
while (foo.good()){
string bar;
getline(foo, bar);
cout << bar << endl;
}
我立刻被指出here并被告知从不测试good
。很明显,这是我无法理解的,但我想正确地进行文件I / O.
我用几个示例测试了我的代码,无法使good
- 测试代码失败。
首先(正确打印,以新行结尾):
bleck 1
blee 1 2
等等
以新的一行结束
第二个(正确打印,以最后一行结尾):
bleck 1
blee 1 2
等等 这不会以新的一行结束
第三个是空文件(打印正确,只有一个换行符。)
第四个是丢失的文件(这没有正确打印。)
有人可以通过一个演示为什么 good
的示例来帮助我 - 不应该进行测试吗?
答案 0 :(得分:6)
他们错了。口头禅永远不会测试.eof()
&#39;。
即使这种口头禅太过分了,因为两者都有助于在提取失败后诊断流的状态。
所以咒语应该更像是
在您尝试继续阅读之前,请不要使用
good()
或eof()
来检测eof
fail()
和bad()
当然,在使用流之前可以有效地使用stream.good
(例如,如果流是尚未成功打开的文件流)
然而,两者都经常 滥用 来检测输入的结束,而不是它的工作方式。
一个典型的例子,说明为什么你不应该使用这种方法:
std::istringstream stream("a");
char ch;
if (stream >> ch) {
std::cout << "At eof? " << std::boolalpha << stream.eof() << "\n";
std::cout << "good? " << std::boolalpha << stream.good() << "\n";
}
打印
false
true
答案 1 :(得分:2)
其他答案已经涵盖了这一点,但为了完整起见,我将简要介绍一下。
唯一的功能差异while(foo.good()) { // effectively same as while(foo) {
getline(foo, bar);
consume(bar); // consume() represents any operation that uses bar
}
和
while(getline(foo, bar)){
consume(bar);
}
当文件中没有行时,前者会做一个额外的循环,使得这种情况与一个空行的情况无法区分。我认为这不是通常期望的行为。但我认为这是意见问题。
正如他所说,咒语是 overboard 。这是一个简化。真正重要的是,在测试失败或至少EOF(以及读取之前的任何测试无关紧要)之前,您不得consume()
读取流的结果。这是人们在循环条件下测试good()
时容易做的事情。
但是,关于getline()
的问题是,它会在内部测试EOF,即使只读取了EOF,也会返回一个空字符串。因此,前一个版本可能大致类似于跟随伪c ++:
while(foo.good()) {
// inside getline
bar = ""; // Reset bar to empty
string sentry;
if(read_until_newline(foo, sentry)) {
// The streams state is tested implicitly inside getline
// after the value is read. Good
bar = sentry // The read value is used only if it's valid.
// ... // Otherwise, bar is empty.
consume(bar);
}
我希望这说明了我想说的话。可以说在 getline()
内有一个“正确”的读取循环版本。这就是为什么即使外部循环不符合规范,使用readline也至少部分地满足了规则。
但是,对于其他阅读方法,违反规则会受到更多伤害。考虑:
while(foo.good()) {
int bar;
foo >> bar;
consume(bar);
}
总是总是获得额外的迭代,该迭代中的bar
未初始化!
因此,简而言之,while(foo.good())
在您的情况下是可以的,因为getline()
与某些其他读取函数不同,在读取EOF位后将输出保留为有效状态。并且因为当文件为空时你不在乎甚至不希望额外的迭代。
答案 2 :(得分:1)
good()
和eof()
都会在您的代码中为您提供额外的一行。如果您有一个空白文件并运行:
std::ifstream foo1("foo1.txt");
std::string line;
int lineNum = 1;
std::cout << "foo1.txt Controlled With good():\n";
while (foo1.good())
{
std::getline(foo1, line);
std::cout << lineNum++ << line << std::endl;
}
foo1.close();
foo1.open("foo1.txt");
lineNum = 1;
std::cout << "\n\nfoo1.txt Controlled With getline():\n";
while (std::getline(foo1, line))
{
std::cout << line << std::endl;
}
您将获得的输出是
foo1.txt Controlled With good():
1
foo1.txt Controlled With getline():
这证明它无法正常工作,因为永远不应该读取空白文件。知道这一点的唯一方法是使用读取条件,因为流在第一次读取时始终是好的。
答案 3 :(得分:1)
使用foo.good()
只是告诉您上一次读取操作工作正常,下一次操作也可以正常工作。 .good()
检查给定点的流状态。它不检查是否到达文件末尾。让我们说在读取文件时发生的事情(网络错误,操作系统错误,......)好将失败。这并不意味着文件的结尾已经到达。然而.good()在到达文件末尾时失败,因为流不再能够读取。
另一方面,.eof()
检查文件的末尾是否真正到达。
因此,.good()
可能会在未到达文件末尾时失败。
希望这可以帮助您理解为什么使用.good()
检查文件末尾是一个坏习惯。