为什么我可以使用 Console.ReadLine 阅读超过 254 个字符,而文档建议我不应该这样做?

Why can I read more than 254 characters with Console.ReadLine when the docs suggest that I shouldn't be able to?

docs 对于 Console.ReadLine 说:

By default, the method reads input from a 256-character input buffer. Because this includes the Environment.NewLine character(s), the method can read lines that contain up to 254 characters. To read longer lines, call the OpenStandardInput(Int32) method.

但是,我可以阅读更多的字符。 运行 一个简单的程序,例如:

string s = Console.ReadLine();
Console.WriteLine(s);
Console.WriteLine(s.Length);

Console.ReadKey();

输入如下:

aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjj

返回长度为 500 的相同输入。

可运行示例 here

当时的文档是否过时了,或者 "by default" 关键词在这里?


一个更新: Jeremy 发现 source code.

中定义的限制为 4096

我已验证 .NET Core 应用程序只会从标准输入读取前 4094 个字符(不包括换行符)。

就我而言,我实际上有一个 .NET Core 3.1 进程启动 .NET Framework 4.6 进程,重定向其 StandardOut 和 StandardIn。我已经验证 .NET Framework 进程可以通过 Console.ReadLine() 成功读取 10 亿个字符,其中 .NET Core 3.1 进程通过 fwProcess.StandardInput.WriteLine(Serialize(<some stuff>));

发送 Framework 进程内容

当 .NET Framework 进程替换为 .NET Core 进程时,这也适用。

因此,重定向 stdout/stdin 时似乎不适用 256 个字符的限制,但如果有人能找到明确的 proof/docs 来解释这一点,我将不胜感激。如果仍然有限制(不包括 OutOfMemory 情况),但它是 11 亿个字符,我想知道。我还想知道这是否取决于平台(我在 Windows 10)。

如果有帮助,这就是我的代码 运行。

ConsoleApp1:

ProcessStartInfo processInfo = new ProcessStartInfo {
    CreateNoWindow = true,
    FileName = "ConsoleApp2.exe",
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardInput = true
};

StringBuilder s = new StringBuilder();
var proc = Process.Start(processInfo);

int n = 1_000_000_000;
for (int i = 0; i < n; i++)
    s.Append("a");

proc.StandardInput.WriteLine(s.ToString());
string s = proc.StandardOutput.ReadLine();
Console.WriteLine(s.Length == n); // logs True

Console.ReadKey();

ConsoleApp2:

string s = Console.ReadLine();
Console.WriteLine(s);

转述自here

The default cmd console mode is "ENABLE_LINE_INPUT", which means that when code issues a ::ReadFile call against stdin, ::ReadFile doesn't return to the caller until it encounters a carriage return. But the call to ReadFile only has a limited size buffer that was passed to it. Which means that cmd looks at the buffer size provided to it, and determines based on that how many characters long the line can be... if the line were longer, it wouldn't be able to store all the data into the buffer.

打开 Console.In 时使用的默认缓冲区大小现在为 4096 (source)

文档是开源的,available here 如果您想提交问题或拉取请求。

重定向 StandardOut/StandardIn 时,此限制不适用。来自 here:

The limit is how much memory you pass in.