[英]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 中说:
提取并存储字符,直到发生以下情况之一:
- 输入序列出现文件结束(在这种情况下 function 调用 setstate(eofbit));
- traits::eq(c, delim) 用于下一个可用的输入字符 c (在这种情况下输入字符被提取但不存储);
- 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,程序正忙着一行一行地打印空;-)。
结论
getline(istream, string)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.