繁体   English   中英

在 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)没有按照您(或我,直到我调试它)认为的那样去做。 是的,它读到下一个换行符; 它在输入中留下了换行符!

下次调用 get() 时,它将立即看到换行符并在缓冲区中返回一个空行,直到永远。

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

EOF 问题

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

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

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

遇到 EOF 后的下一次读取将失败,因为无法提取数据:毕竟,读取 position 仍处于 EOF。 被认为是读取失败。 条件错误并退出循环,这正是我们的意图。

缓冲区大小问题

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

提取并存储字符,直到发生以下情况之一:

  1. 输入序列出现文件结束(在这种情况下 function 调用 setstate(eofbit));
  2. traits::eq(c, delim) 用于下一个可用的输入字符 c (在这种情况下输入字符被提取但不存储);
  3. n 小于 1 或 n - 1 个字符被存储(在这种情况下 function 调用 setstate(failbit))。

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

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

行结束问题

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

控制台问题;-)

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

结论

  • 调试你的程序。 使用 VS 非常容易。
  • 使用getline(istream, string)
  • 在 while 循环中将输入函数(通常是流)的返回值用作 boolean:“只要您可以提取任何输入,就使用该输入。”
  • 当心行尾问题。
  • 考虑 C I/O (printf, scanf) 对于任何不平凡的事情(我没有在我的回答中讨论这个,但我认为这是很多人所做的)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM