在C ++中从文件中读取行的首选模式是什么?

时间:2011-08-28 04:36:47

标签: c++ file-io

我在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)) {
  // ...

当然,我可以添加一些检查以确保文件存在并打开。除了异常处理之外,是否有理由更喜欢更详细的第一种模式?你的标准做法是什么?

5 个答案:

答案 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;
}