如何在 C++ 中从 cin 读取直到 EOF

How to read until EOF from cin in C++

提问人: 提问时间:10/15/2008 最后编辑:5 revs, 3 users 60%Guille 更新时间:10/25/2023 访问量:277298

问:

我正在编写一个程序,该程序直接从用户输入中读取数据,并且想知道如何(没有循环)从标准输入中读取所有数据,直到 EOF。我正在考虑使用但不是真正的 EOF 字符,它只是读取直到 EOF 或 ,以先到者为准。cin.get( input, '\0' )'\0''\0'

还是使用循环是唯一的方法?如果是这样,最好的方法是什么?

C++ 输入 IOSTREAM

评论


答:

2赞 luke 10/15/2008 #1

您可以使用 std::istream::getline() 函数(或者最好是适用于 std::string 的版本)来获取整行。两者都具有允许您指定分隔符(行尾字符)的版本。字符串版本的默认值为“\n”。

99赞 trotterdylan 10/15/2008 #2

从中读取可变数量数据的唯一方法是使用循环。我一直发现 std::getline() 函数工作得很好:stdin

std::string line;
while (std::getline(std::cin, line))
{
    std::cout << line << std::endl;
}

默认情况下,读取直到换行符。您可以指定替代终止字符,但 EOF 本身不是字符,因此您不能简单地调用一次 。getline()getline()

评论

10赞 Zoccadoum 3/29/2016
这里需要注意的一点是,当您从通过 stdin 管道传入的文件中读取时,这个和大多数给出的答案都会在输入的末尾附加一个额外的换行符。并非所有文件都以换行符结尾,但循环的每次迭代都会将“std::endl”追加到流中。在大多数情况下,这可能不是问题,但如果文件完整性是一个问题,这可能会再次困扰您。
3赞 loxaxs 8/16/2017
这不应该是被点赞最多的答案。请参阅下面的社区 wiki 答案。另外,也许看到这个问题:stackoverflow.com/questions/3203452/......
58赞 KeithB 10/15/2008 #3

您可以使用流迭代器在没有显式循环的情况下执行此操作。我敢肯定它在内部使用了某种循环。

#include <string>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>

int main()
{
// don't skip the whitespace while reading
  std::cin >> std::noskipws;

// use stream iterators to copy the stream to a string
  std::istream_iterator<char> it(std::cin);
  std::istream_iterator<char> end;
  std::string results(it, end);

  std::cout << results;
}

评论

3赞 Michael Burr 10/15/2008
好。至于“我确信它在内部使用某种循环”——任何解决方案都会。
0赞 Multisync 9/7/2017
这似乎从输入中删除了换行符,即使它们正好出现在中间。
71赞 Degvik 10/15/2008 #4

使用循环:

#include <iostream>
using namespace std;
...
// numbers
int n;
while (cin >> n)
{
   ...
}
// lines
string line;
while (getline(cin, line))
{
   ...
}
// characters
char c;
while (cin.get(c))
{
   ...
}

资源

0赞 2 revs, 2 users 57%Bryan #5
while(std::cin) {
 // do something
}

评论

11赞 Kerrek SB 2/20/2017
这是一个可怕的答案灾难,因为它几乎肯定会导致错误的代码。
0赞 matusf 10/2/2018
@KerrekSB为什么它几乎肯定会导致错误的代码呢?
1赞 Kerrek SB 10/3/2018
@MatúšFerech:因为它强烈建议它不包含对 I/O 操作返回值的额外检查,并且它包含的检查毫无意义。// do something
3赞 liborm #6

悲伤的旁注:我决定使用 C++ IO 与基于 boost 的代码保持一致。从这个问题的答案中,我选择了.在 cygwin (mintty) 中使用 g++ 版本 4.5.3 (-O3),我获得了 2 MB/s 的吞吐量。Microsoft Visual C++ 2010 (/O2) 使相同的代码达到 40 MB/s。while (std::getline(std::cin, line))

将 IO 重写为纯 C 后,两个测试编译器的吞吐量都跃升至 90 MB/s。对于任何大于 10 MB 的输入,这都会有所不同......while (fgets(buf, 100, stdin))

评论

0赞 R D 11/20/2017
无需将代码重写为纯 C,只需在 while 循环之前添加一个即可。 如果您交错阅读和写作,也可能会有所帮助。std::ios::sync_with_stdio(false);cin.tie(NULL);
0赞 3 revsuberwulu #7

等等,我理解正确吗?您正在使用 cin 进行键盘输入,并且想要在用户输入 EOF 字符时停止读取输入?为什么用户会键入 EOF 字符?或者您的意思是要停止从EOF的文件中读取?

如果您实际上尝试使用 cin 来读取 EOF 字符,那么为什么不直接将 EOF 指定为分隔符呢?

// Needed headers: iostream

char buffer[256];
cin.get( buffer, '\x1A' );

如果要停止从 EOF 中的文件读取,则只需使用 getline 并再次指定 EOF 作为分隔符。

// Needed headers: iostream, string, and fstream

string buffer;

    ifstream fin;
    fin.open("test.txt");
    if(fin.is_open()) {
        getline(fin,buffer,'\x1A');

        fin.close();
    }
0赞 0xbadf00d #8

一种选择是使用容器,例如

std::vector<char> data;

并将所有输入重定向到此集合中,直到收到为止,即EOF

std::copy(std::istream_iterator<char>(std::cin),
    std::istream_iterator<char>(),
    std::back_inserter(data));

但是,使用的容器可能需要过于频繁地重新分配内存,否则当系统内存不足时,您将以异常结束。为了解决这些问题,您可以保留固定数量的元素并单独处理这些数量的元素,即std::bad_allocN

data.reserve(N);    
while (/*some condition is met*/)
{
    std::copy_n(std::istream_iterator<char>(std::cin),
        N,
        std::back_inserter(data));

    /* process data */

    data.clear();
}
6赞 FrankHB #9

可能最简单且通常有效:

#include <iostream>
int main()
{
    std::cout << std::cin.rdbuf();
}

如果需要,请使用其他类型的流,例如作为缓冲区,而不是此处的标准输出流。std::ostringstream

评论

1赞 ribamar 12/2/2015
你们已经知道了,但可能对某些人有所帮助:.您拥有所有输入(如果输入太大,请小心)std::ostringstream std_input; std_input << std::cin.rdbuf(); std::string s = std_input.str()sstd::string
45赞 2 revs, 2 users 93%Richard Smith #10

在研究了 KeithB 的解决方案后,我发现了 std:istreambuf_iteratorstd::istream_iterator

测试程序将所有管道输入读入字符串,然后再次写出:

#include <iostream>
#include <iterator>
#include <string>

int main()
{
  std::istreambuf_iterator<char> begin(std::cin), end;
  std::string s(begin, end);
  std::cout << s;
}

评论

9赞 Kerrek SB 2/20/2017
这可能应该是规范的答案。
3赞 Multisync 9/7/2017
投了反对票。那么,与 KeithB 的解决方案相比,它有什么优点或缺点呢?是的,您使用的是 an 而不是 ,但是为了什么?std::istreambuf_iteratorstd::istream_iterator
2赞 Sopel 11/19/2018
std::istreambuf_iterator 默认跳过空格,速度更快
0赞 dimon-ksi #11

一行循环:

for( std::string line; std::getline(std::cin, line); std::cout << line << std::endl );