简体   繁体   English

在 C++ 中逐行读取一个文件

[英]Read a file line by line in C++

I wrote the following C++ program to read a text file line by line and print out the content of the file line by line.我写了下面这个C++程序逐行读取一个文本文件,并逐行打印出文件内容。 I entered the name of the text file as the only command line argument into the command line.我将文本文件的名称作为唯一的命令行参数输入到命令行中。

#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;
}

However, when I ran this code in Visual Studio, the Debug Console was completely blank.然而,当我在 Visual Studio 中运行这段代码时,调试控制台是完全空白的。 What's wrong with my code?我的代码有什么问题?

Apart from the errors mentioned in the comments, the program has a logical error because istream& istream::get(char* s, streamsize n) does not do what you (or I, until I debugged it) thought it does.除了评论中提到的错误之外,该程序还有一个逻辑错误,因为istream& istream::get(char* s, streamsize n)没有按照您(或我,直到我调试它)认为的那样去做。 Yes, it reads to the next newline;是的,它读到下一个换行符; but it leaves the newline in the input!它在输入中留下了换行符!

The next time you call get(), it will see the newline immediately and return with an empty line in the buffer, for ever and ever.下次调用 get() 时,它将立即看到换行符并在缓冲区中返回一个空行,直到永远。

The best way to fix this is to use the appropriate function, namely istream::getline() which extracts, but does not store the newline.解决此问题的最佳方法是使用适当的 function,即istream::getline()提取但不存储换行符。

The EOF issue EOF 问题

is worth mentioning.值得一提。 The canonical way to read lines (if you want to write to a character buffer) is读取行的规范方法(如果你想写入字符缓冲区)是

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

getline() returns a reference to the stream which in turn has a conversion function to bool, which makes it usable in a boolean expression like this. getline() 返回对 stream 的引用,它又将 function 转换为 bool,这使得它可以在这样的 boolean 表达式中使用。 The conversion is true if input could be obtained.如果可以获得输入,则转换为真。 Interestingly, it may have encountered the end of file, and f.eof() would be true;有趣的是,它可能遇到文件末尾,f.eof() 为真; but that alone does not make the stream convert to false .但仅此一点并不能使 stream 转换为false As long as it could extract at least one character it will convert to true , indicating that the last input operation made input available, and the loop will work as expected.只要它可以提取至少一个字符,它就会转换为true ,表示最后一个输入操作使输入可用,并且循环将按预期工作。

The next read after encountering EOF would then fail because no data could be extracted: After all, the read position is still at EOF.遇到 EOF 后的下一次读取将失败,因为无法提取数据:毕竟,读取 position 仍处于 EOF。 That is considered a read failure.被认为是读取失败。 The condition is wrong and the loop is exited, which was exactly the intent.条件错误并退出循环,这正是我们的意图。

The buffer size issue缓冲区大小问题

is worth mentioning, as well.也值得一提。 The standard draft says in 30.7.4.3:标准草案在 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));输入序列出现文件结束(在这种情况下 function 调用 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); traits::eq(c, delim) 用于下一个可用的输入字符 c (在这种情况下输入字符被提取但不存储);
  3. n is less than one or n - 1 characters are stored (in which case the function calls setstate( failbit)). n 小于 1 或 n - 1 个字符被存储(在这种情况下 function 调用 setstate(failbit))。

The conditions are tested in that order, which means that if n-1 characters have been stored and the next character is a newline (the default delimiter), the input was successful (and the newline is extracted as well).按照这个顺序测试条件,也就是说如果已经存储了n-1个字符,并且下一个字符是换行符(默认分隔符),则输入成功(并且换行符也被提取)。

This means that if your file contains a single line 123 you can read that successfully with f.getline(buf, 4) , but not a line 1234 (both may or may not be followed by a newline).这意味着,如果您的文件包含单行123 ,您可以使用f.getline(buf, 4)成功读取该行,但不能读取第1234行(两者后面可能有也可能没有换行符)。

The line ending issue行结束问题

Another complication here is that on Windows a file created with a typical editor will have a hidden carriage return before the newline, ie a line actually looks like "123\r\n" ("\r" and "\n" each being a single character with the values 13 and 10, respectively).这里的另一个复杂情况是,在 Windows 上,使用典型编辑器创建的文件在换行符之前会有一个隐藏的回车符,即一行实际上看起来像“123\r\n”(“\r”和“\n”都是值分别为 13 和 10 的单个字符)。 Because you opened the file with the binary flag the program will see the carriage return;因为您使用二进制标志打开文件,程序将看到回车; all lines will contain that "invisible" character, and the number of visible characters fitting in the buffer will be one shorter than one would assume.所有行都将包含该“不可见”字符,并且适合缓冲区的可见字符数将比假设的少一个。

The console issue;-)控制台问题;-)

Oh, and your Console was not entirely empty;哦,您的控制台并不完全是空的; it's just that modern computers are too fast and the first line which was probably printed (it was in my case) scrolled away faster than anybody could switch windows. When I looked closely there was a cursor in the bottom left corner where the program was busy printing line after line of nothing;-).只是现代计算机太快了,可能打印的第一行(在我的情况下)滚动离开的速度比任何人切换 windows 的速度都快。当我仔细观察时,左下角有一个 cursor,程序正忙着一行一行地打印空;-)。

The conclusion结论

  • Debug your programs.调试你的程序。 It's very easy with VS.使用 VS 非常容易。
  • Use getline(istream, string) .使用getline(istream, string)
  • Use the return value of input functions (typically the stream) as a boolean in a while loop: "As long as you can extract any input, use that input."在 while 循环中将输入函数(通常是流)的返回值用作 boolean:“只要您可以提取任何输入,就使用该输入。”
  • Beware of line ending issues.当心行尾问题。
  • Consider C I/O (printf, scanf) for anything non-trivial (I didn't discuss this in my answer but I think that's what many people do).考虑 C I/O (printf, scanf) 对于任何不平凡的事情(我没有在我的回答中讨论这个,但我认为这是很多人所做的)。

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

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