【发布时间】:2019-08-21 10:09:26
【问题描述】:
我正在尝试在 Windows 上使用 C++ 高效地从标准输入读取数据,这意味着最好是大块。这可以通过以下方式完成:
ReadFile(GetStdHandle(STD_INPUT_HANDLE), buf, bytestoread, &bytesread, 0);
或
read(0, buf, bytestoread);
但在这两种情况下,它仅在 bytestoread 设置为非常小的数字时才有效,例如50;如果设置为更大的数字,例如一兆字节,调用失败并出现“空间不足”错误,好像数据没有直接进入我提供的缓冲区,而是通过一些固定大小的内部缓冲区复制。无论输入是通过管道传输还是在控制台上键入,都是如此。
Windows 是否只是限制了进程一次可以从标准输入读取的块大小?如果是这样,保证工作的最大块大小是多少?
显示问题的完整程序:
#include <errno.h>
#include <io.h>
#include <stdio.h>
#include <string.h>
char buf[1000000];
int main(int argc, char **argv) {
auto r = read(0, buf, sizeof buf);
if (r < 0)
perror("read");
return 0;
}
【问题讨论】:
-
Windows 不受限制。但这是设备(到该点
STD_INPUT_HANDLE)特定的。控制台、管道、文件系统文件的结果可能不同 -
@RbMm 好的,那么什么值可以保证在所有情况下都有效?
-
这是一种不寻常的控制台输入方式,当然我们都想知道这样做的意义何在。但可以肯定的是,控制台输入是独立缓冲的,在您按下 Enter 键之前什么都不会发生。 64KB 是控制台的流行限制。当然,您必须修改 Get/SetConsoleMode(),并期望您至少必须关闭 ENABLE_LINE_INPUT 选项。
-
@rwallace 确实:一个兆字节的缓冲区,接受一行输入而不会出错。当我通过管道输入大量数据时,我会收到一个不同的错误,因为即使在管道关闭后,Windows 仍会尝试写入管道。那是因为我们实际上应该在一个循环中读取,直到我们读取所有数据——但这是一个完全不同的问题。我使用 Embarcadero C++Builder 编译,它使用不同的 C 运行时。我会看看是否可以尝试使用 Microsoft C++。
-
@rwallace 我现在使用 Visual Studio 2008 的编译器进行编译。 “echo hello | foo”有效,但现在只有“foo”说“阅读:没有足够的空间”!有趣的。 (我使用的是标准的 Windows 终端)。实际上,我的原始程序也发生了同样的情况:只有没有管道输入的程序说“读取:内存不足”。显然我以前没有尝试过。