我正在使用标准的C ++ fstreams库,我想知道正确使用它的方式是什么。根据经验,我想出了一个小的使用协议,但我不是很确定。为了简单起见,我们假设我只想读取一个文件,例如,过滤其内容并将其放在另一个文件上。我的例程大致如下:
istream i("filename")
变量来打开文件; i.good()
或i.is_open()
以处理打开时出现问题的情况,例如,因为该文件不存在;之后,我认为该文件存在,我没事; i.peek()
然后再呼叫i.good()
或i.eof()
以排除文件为空的情况;之后,我认为我实际上有一些东西要读; >>
或其他任何东西来阅读文件的内容,eof()
来检查我是否已经结束; 这是一个理智(正确,最小)的例程吗?在否定的情况下,你会如何解决它?请注意,我不考虑比赛 - 同步是另一回事。
答案 0 :(得分:4)
我会消除peek / good / eof(你的第三步)。只需尝试读取您的数据,并检查尝试读取是成功还是失败。同样,在第四步中,只需检查您的尝试读取是否成功。
典型代码如下:
std::ifstream i("whatever");
if (!i)
error("opening file");
while (i >> your_data)
process(your_data);
if (!i.eof())
// reading failed before end of file
答案 1 :(得分:3)
它比你描述的简单。前两个步骤很好(但如果你按照我的其他建议,第二步是没有必要的)。然后你应该尝试提取,但是使用提取作为循环或if
语句的条件。例如,如果文件被格式化为所有相同格式的一系列行(或其他分隔序列),您可以这样做:
std::string line;
while (std::getline(i, line)) {
// Parse line
}
循环体只会在行提取工作时执行。当然,您需要检查循环内线的有效性。
如果您要对流进行一系列提取或其他操作,则可以将它们置于if
条件下,如下所示:
if (i >> some_string &&
i.get() == '-' &&
i >> some_int) {
// Use some_string and some_int
}
如果第一次提取失败,i.ignore()
由于&&
的短路评估而无法执行。 if
语句的主体只有在两次提取都成功时才会执行。如果你有两个提取,你当然可以链接它们:
if (i >> some_string >> some_int) {
// Use some_string and some_int
}
如果第一个提取失败,则不会发生链中的第二次提取。提取失败会使流处于一种状态,其中所有后续提取也会自动失败。
出于这个原因,将流操作置于if
条件之外,然后检查流的状态也很好:
i >> some_string >> some_int;
if (i) {
// Use some_string and some_int
}
使用这两种方法,您不必检查流的某些问题。检查eof()
的流并不一定意味着下一次读取将失败。一个常见的情况是当人们使用以下不正确的提取循环时:
// DO NOT DO THIS
while (!i.eof()) {
std::getline(i, line)
// Do something with line
}
大多数文本文件以文本编辑器隐藏的最后一行新行结束。当您从文本文件中读取行时,在最后一次迭代中,您还没有到达文件末尾,因为仍然需要读取\n
。因此循环继续,尝试提取不存在的下一行并拧紧。人们经常将其视为“两次读取文件的最后一行”。