C++逐行读取文件

Read a file line by line in C++

我写了下面的C++程序来逐行读取一个文本文件,并逐行打印出文件的内容。我在命令行中输入了文本文件的名称作为唯一的命令行参数。

#include <iostream>
#include <fstream>
using namespace std;

int main(int argc, char* argv[])
{
    char buf[255] = {};
    if (argc != 2)
    {
        cout << "Invalid number of files." << endl;
        return 1;
    }
    ifstream f(argv[1], ios::in | ios::binary);
    if (!f)
    {
        cout << "Error: Cannot open file." << endl;
        return 1;
    }

    while (!f.eof())
    {
        f.get(buf,255);
        cout << buf << endl;
    }
    f.close();
    return 0;
}

然而,当我运行这段代码在Visual Studio时,调试控制台是完全空白的。我的代码有什么问题?

除了评论中提到的错误外,该程序还有一个逻辑错误,因为 istream& istream::get(char* s, streamsize n) 没有按照您(或我,直到我调试它)认为的那样去做。是的,它读到下一个换行符;但是 it leaves the newline in the input!

下次您调用 get() 时,它会立即看到换行符并且 return 缓冲区中有一个空行,永远永远。

解决此问题的最佳方法是使用适当的函数,即 istream::getline(),它 提取但不存储 换行符。

EOF 问题

值得一提。读取行的规范方法(如果你想写入字符缓冲区)是

  while (f.getline(buf, bufSz))
  {
    cout << buf << "\n";
  }

getline() returns 对流的引用,它又具有到 bool 的转换函数,这使得它可以在这样的布尔表达式中使用。如果可以获得输入,则转换为真。有趣的是,它可能遇到文件末尾,f.eof() 为真;但仅此一项并不能使流转换为 false。只要它能提取至少一个字符,它就会转换为 true,表明最后一个输入操作使输入可用,并且循环将按预期工作。

遇到EOF后的下一次读取会失败,因为无法提取数据:毕竟读取位置还在EOF。 被认为是读取失败。条件错误退出循环,正合本意

缓冲区大小问题

也值得一提。标准草案在 30.7.4.3 中说:

Characters are extracted and stored until one of the following occurs:

  1. end-of-file occurs on the input sequence (in which case the function calls setstate(eofbit));
  2. traits::eq(c, delim) for the next available input character c (in which case the input character is extracted but not stored);
  3. n is less than one or n - 1 characters are stored (in which case the function calls setstate( failbit)).

条件按此顺序测试,这意味着如果已存储 n-1 个字符并且下一个字符是换行符(默认分隔符),则输入是成功(换行符也被提取)。

这意味着,如果您的文件包含单行 123,您可以使用 f.getline(buf, 4) 成功读取该行,但不能读取行 1234(两者后面可能有也可能没有一个换行符)。

行尾问题

这里的另一个复杂情况是,在 Windows 上,使用典型编辑器创建的文件在换行符之前会有一个隐藏的回车符 return,即一行实际上看起来像“123\r\n” (“\r”和“\n”each 是单个字符,其值分别为 13 和 10)。因为您使用二进制标志打开文件,程序将看到回车 return;所有行都将包含该“不可见”字符,并且适合缓冲区的可见字符数将比假设的少一个。

控制台问题;-)

哦,您的控制台并不是完全空的;只是现代计算机速度太快,可能打印的第一行(在我的情况下)滚动离开的速度比任何人都可以切换 windows。当我仔细观察时,在左下角有一个光标,程序正忙着一行一行地打印空 ;-)。

结论

  • 调试你的程序。使用 VS 非常简单。
  • 使用getline(istream, string).
  • 使用输入函数的return值(通常是流) 作为 while 循环中的布尔值:“只要您可以提取任何输入,就使用该输入。”
  • 注意行尾问题。
  • 考虑 C I/O (printf, scanf) 任何重要的事情(我没有在我的回答中讨论这个,但我认为这是很多人所做的)。