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


79

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

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

Answers:


78

读取变量数据的唯一方法stdin是使用循环。我一直发现该std::getline()功能运行良好:

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

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


8
这里要注意的一点是,当您从通过stdin传递的文件中读取内容时,这和给出的大多数答案将在输入的末尾附加一个换行符。并非所有文件都以换行符结尾,但是循环的每次迭代都会在流中附加“ std :: endl”。在大多数情况下,这可能不是问题,但是如果文件完整性成为问题,则可能会再次咬住您。
Zoccadoum's

1
这不应该是最受支持的答案。请参阅以下社区Wiki答案。另外,也许看到这个问题:stackoverflow.com/questions/3203452/…–
loxaxs

50

使用循环:

#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))
{
   ...
}

资源


49

通过使用流迭代器,可以在没有显式循环的情况下进行操作。我确定它在内部使用了某种循环。

#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

这似乎从输入中删除了换行符,即使它们出现在中间。
Multisync

25

研究了KeithB的解决方案后std::istream_iterator,我发现了std:istreambuf_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;
}

5
这可能是规范的答案。
Kerrek SB

2
不赞成投票。那么,与KeithB解决方案相比,优缺点是什么?是的,您使用std::istreambuf_iterator而不是std::istream_iterator,但是用什么呢?
Multisync

std :: istreambuf_iterator默认情况下会跳过空格,并且可以更快
Sopel

5

可能最简单且通常有效:

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

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


你们已经知道,但可能对某些人有帮助std::ostringstream std_input; std_input << std::cin.rdbuf(); std::string s = std_input.str()。您已将所有输入都输入了sstd::string输入太大请小心 )
ribamar


2

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

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


无需将代码重写为纯C语言,只需std::ios::sync_with_stdio(false);在while循环之前添加一个。cin.tie(NULL);如果您交错阅读和写作,也可能会有所帮助。
RD

0
while(std::cin) {
 // do something
}

8
这是一个可怕的答案灾难,因为实际上可以保证导致错误的代码。
Kerrek SB

@KerrekSB为什么实际上可以保证导致错误的代码?
matusf '18 -10-1

1
@MatúšFerech:因为它强烈建议它// do something不包含I / O操作返回值的其他检查,并且它所包含的检查是没有意义的。
Kerrek SB '18 -10-3

0

等一下,我理解正确吗?您正在使用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

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

std::vector<char> data;

重定向所有输入到该集合,直到EOF被接收,即

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

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

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();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.