【发布时间】:2010-09-17 03:36:07
【问题描述】:
我正在编写一个直接从用户输入读取数据的程序,并且想知道如何(没有循环)从标准输入读取所有数据,直到 EOF。我正在考虑使用cin.get( input, '\0' ),但'\0' 并不是真正的EOF 字符,它只会读取到EOF 或'\0',以先到者为准。
或者使用循环是唯一的方法?如果是这样,最好的方法是什么?
【问题讨论】:
我正在编写一个直接从用户输入读取数据的程序,并且想知道如何(没有循环)从标准输入读取所有数据,直到 EOF。我正在考虑使用cin.get( input, '\0' ),但'\0' 并不是真正的EOF 字符,它只会读取到EOF 或'\0',以先到者为准。
或者使用循环是唯一的方法?如果是这样,最好的方法是什么?
【问题讨论】:
从stdin 读取可变数量数据的唯一方法是使用循环。我一直发现std::getline() 函数效果很好:
std::string line;
while (std::getline(std::cin, line))
{
std::cout << line << std::endl;
}
默认情况下,getline() 会一直读取到换行符。您可以指定替代终止字符,但 EOF 本身不是字符,因此您不能简单地调用 getline()。
【讨论】:
使用循环:
#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))
{
...
}
【讨论】:
您可以使用流迭代器在没有显式循环的情况下做到这一点。我确信它在内部使用了某种循环。
#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;
}
【讨论】:
在使用std::istream_iterator研究了KeithB的解决方案后,我发现了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;
}
【讨论】:
std::istreambuf_iterator 而不是std::istream_iterator,但这是为了什么?
可能最简单且通常有效:
#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()。 s 中有所有输入(如果输入太大,请注意 std::string)
悲伤的旁注:我决定使用 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 的输入都会有所不同...
【讨论】:
std::ios::sync_with_stdio(false);。 cin.tie(NULL); 如果您将阅读和写作交错,也可能会有所帮助。
您可以使用std::istream::getline()(或者最好是version that works on std::string)函数来获取整行。两者都有允许您指定分隔符(行尾字符)的版本。字符串版本的默认值为 '\n'。
【讨论】:
while(std::cin) {
// do something
}
【讨论】:
// do something不包含对I/O操作返回值的额外检查,它包含的检查是没有意义的。
等等,我理解正确吗?您正在使用 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();
}
【讨论】:
一种选择是使用容器,例如
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();
}
【讨论】: