用于从标准输入读取的 Win32 缓冲区大小

Win32 buffer size for read from stdin

我正在尝试在 Windows 上用 C++ 高效地从标准输入读取数据,这意味着最好是大块读取。这可以通过以下方式完成:

ReadFile(GetStdHandle(STD_INPUT_HANDLE), buf, bytestoread, &bytesread, 0);

read(0, buf, bytestoread);

但在这两种情况下,它仅在 bytestoread 设置为非常小的数字时有效,例如50;如果设置为更大的数字,例如一兆字节,调用失败并出现 'not enough space' 错误,就好像数据没有直接进入我提供的缓冲区,而是通过一些固定大小的内部缓冲区复制。无论输入是通过管道还是在控制台上输入,都是如此。

Windows 是否仅限制进程一次可以从 stdin 读取的块大小?如果是这样,保证工作的最大块大小是多少?

显示问题的完整程序:

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

据我所知,是stdin没有限制。它作为一个无尽的流工作,应该提供你需要的尽可能多的存储空间。我看到的唯一选择是您正在使用的内核在某些时候会阻塞

您没有说明您使用的是哪个版本的运行时和 OS,但我无法在 Windows 10 上使用 MSVC 19.16.27031.1 重现此问题。有一些记录在案的原因可能会失败。来自 MSDN documentation of ReadFile:

Characters can be read from the console input buffer by using ReadFile with a handle to console input. The console mode determines the exact behavior of the ReadFile function. By default, the console mode is ENABLE_LINE_INPUT, which indicates that ReadFile should read until it reaches a carriage return. If you press Ctrl+C, the call succeeds, but GetLastError returns ERROR_OPERATION_ABORTED. For more information, see CreateFile.

还有另一种方法可能会导致此错误,与异步有关 I/O,但这似乎不是这里的问题。您可能想用 SetConsoleMode 关闭 ENABLE_LINE_INPUT 标志。该文档还说,如果无法锁定缓冲区的内存页面,调用可能会失败并返回 ERROR_NOT_ENOUGH_QUOTA。但是,你使用静态缓冲区应该不会有这个问题。

如果您正在读取磁盘上的文件,而不是控制台流,您可能会 map it to memory, 消除任何中间缓冲并根据需要加载文件部分,通过与虚拟内存相同的机制。

如果您尝试读取标准输入 binary 您需要的数据:

  1. 设置_setmode( _fileno( stdin), _O_BINARY);
  2. fread( buf, 1, bufSize, stdin)

看看我的类似解决方案 应用程序通过 stdin、油门速度和 将它输出到 stdout.

bin_pipe_throttle