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

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

或者使用循环是唯一的方法吗? 如果是的话,最好的方法是什么?

263183 次浏览

You can use the std::istream::getline() (or preferably the version that works on std::string) function to get an entire line. Both have versions that allow you to specify the delimiter (end of line character). The default for the string version is '\n'.

The only way you can read a variable amount of data from stdin is using loops. I've always found that the std::getline() function works very well:

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

By default getline() reads until a newline. You can specify an alternative termination character, but EOF is not itself a character so you cannot simply make one call to getline().

You can do it without explicit loops by using stream iterators. I'm sure that it uses some kind of loop internally.

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

Using loops:

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

resource

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

Sad side note: I decided to use C++ IO to be consistent with boost based code. From answers to this question I chose while (std::getline(std::cin, line)). Using g++ version 4.5.3 (-O3) in cygwin (mintty) i got 2 MB/s throughput. Microsoft Visual C++ 2010 (/O2) made it 40 MB/s for the same code.

After rewriting the IO to pure C while (fgets(buf, 100, stdin)) the throughput jumped to 90 MB/s in both tested compilers. That makes a difference for any input bigger than 10 MB...

Wait, am I understanding you correctly? You're using cin for keyboard input, and you want to stop reading input when the user enters the EOF character? Why would the user ever type in the EOF character? Or did you mean you want to stop reading from a file at the EOF?

If you're actually trying to use cin to read an EOF character, then why not just specify the EOF as the delimiter?

// Needed headers: iostream


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

If you mean to stop reading from a file at the EOF, then just use getline and once again specify the EOF as the delimiter.

// Needed headers: iostream, string, and fstream


string buffer;


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


fin.close();
}

One option is to a use a container, e.g.

std::vector<char> data;

and redirect all input into this collection until EOF is received, i.e.

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

However, the used container might need to reallocate memory too often, or you will end with a std::bad_alloc exception when your system gets out of memory. In order to solve these problems, you could reserve a fixed amount N of elements and process these amount of elements in isolation, i.e.

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();
}

Probable simplest and generally efficient:

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

If needed, use stream of other types like std::ostringstream as buffer instead of standard output stream here.

After researching KeithB's solution using std::istream_iterator, I discovered the std:istreambuf_iterator.

Test program to read all piped input into a string, then write it out again:

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


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