我在C ++教程中至少看到了两种从文件中读取行的方法:
std::ifstream fs("myfile.txt");
if (fs.is_open()) {
while (fs.good()) {
std::string line;
std::getline(fs, line);
// ...
和
std::ifstream fs("myfile.txt");
std::string line;
while (std::getline(fs, line)) {
// ...
当然,我可以添加一些检查以确保文件存在并打开。除了异常处理之外,是否有理由更喜欢更详细的第一种模式?你的标准做法是什么?
答案 0 :(得分:25)
while (std::getline(fs, line))
{}
这不仅正确,而且更可取 因为它是惯用的。
我假设在第一种情况下,您未在fs
之后std::getline()
检查if(!fs) break;
或等同的内容。因为如果你不这样做,那么第一种情况就完全错了。或者如果你这样做,那么第二个仍然更可取,因为它更简洁明了。
在尝试从流中读取之后,应该使用}函数{em};它用于检查尝试是否成功。在你的第一种情况下,你不这样做。在good()
之后,您认为读取成功,甚至没有检查std::getline()
返回的内容。此外,您似乎假设如果fs.good()
返回true,fs.good()
将成功读取流中的一行。你正朝着相反的方向前进:事实是,如果std::getline
成功从流中读取一行,那么std::getline
将返回fs.good()
。
cplusplus上的文档说明了good()
,
如果没有设置流的错误标志(eofbit,failbit和badbit),则该函数返回true。
也就是说,当您尝试从输入流中读取数据时,如果尝试失败,则仅设置失败标志并且true
返回good()
作为失败的指示。
如果您想将false
变量的范围仅限于循环内部,那么您可以将line
循环写为:
for
注意:在阅读@ john的解决方案后,我想到了这个解决方案,但我认为它比他的版本更好。
在这里阅读详细解释,为什么第二个更可取和惯用:
或者阅读@Jerry Coffin撰写的精美博客:
答案 1 :(得分:3)
将此视为对纳瓦兹已经出色的答案的延伸评论。
关于你的第一个选择,
while (fs.good()) {
std::string line;
std::getline(fs, line);
...
这有很多问题。问题编号1表示while
条件位于错误的位置并且是多余的。它位于错误的位置,因为fs.good()
表示对文件执行的最近操作是否正常。暂时的情况应该与即将到来的行动有关,而不是之前的行动。无法知道即将对文件执行的操作是否正常。即将采取的行动fs.good()
没有阅读您的代码以了解即将采取的操作是什么。
问题二是您忽略了std::getline()
的返回状态。如果您立即使用fs.good()
检查状态,那就没问题。所以,稍微修正一下,
while (true) {
std::string line;
if (std::getline(fs, line)) {
...
}
else {
break;
}
}
或者,您可以执行if (! std::getline(fs, line)) { break; }
,但现在循环中间有break
。 Yech。如果可能的话,将退出条件作为循环语句本身的一部分要好得多。
将其与
进行比较std::string line;
while (std::getline(fs, line)) {
...
}
这是用于从文件中读取行的 标准习惯用法。 C中存在一个非常相似的习语。这个习语非常古老,使用非常广泛,并被广泛视为 从文件中读取行的正确方法。
如果您来自禁止有副作用的病症的商店怎么办? (有很多很多编程标准可以做到这一点。)有一种方法可以解决这个问题而不需要在循环方法中间使用中断:
std::string line;
for (std::getline(fs, line); fs.good(); std::getline(fs, line)) {
...
}
并不像休息方式那样丑陋,但大多数人都会认为这不像标准惯用语那样漂亮。
我的建议是使用标准习语,除非某些标准白痴禁止使用它。
<强>附录强>
关于for (std::getline(fs, line); fs.good(); std::getline(fs, line))
:这有两个原因是丑陋的。一个是明显的复制代码块。
不太明显的是,调用getline
然后调用good
会破坏原子性。如果其他一些线程也在从文件中读取怎么办?现在这并不是那么重要,因为C ++ I / O目前不是线程安全的。它将在即将到来的C ++ 11中。打破原子性只是为了让标准的执行者感到高兴是灾难的后果。
答案 2 :(得分:2)
其实我更喜欢另一种方式
for (;;)
{
std::string line;
if (!getline(myFile, line))
break;
...
}
对我来说它读得更好,字符串的范围是正确的(即在使用它的循环内部,而不是在循环之外)
但是你写的第二个是正确的。
答案 3 :(得分:1)
第一个解除分配并在每个循环中重新分配字符串,浪费时间 第二次将字符串写入已存在的空间,删除重新分配和重新分配,使其实际上比第一个更快(更好)。
答案 4 :(得分:-5)
试试这个=&gt;
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main () {
string line;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( myfile.good() )
{
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}