2

The docs for Console.ReadLine say:

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.

However, I can read more than that many characters just fine. Running a simple program like:

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

Console.ReadKey();

with an input like:

aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffgggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjj

yields the same input back with length 500.

Runnable example here.

Are the docs outdated then, or are the words "by default" key here?


An update: Jeremy found a limit of 4096 defined in the source code.

I have verified that a .NET Core app will only read the first 4094 characters from stdin (excluding newlines).

In my case, I actually have a .NET Core 3.1 process that starts a .NET Framework 4.6 process, redirecting its StandardOut and StandardIn. I have verified that the .NET Framework process can successfully read 1 billion characters via Console.ReadLine() where the .NET Core 3.1 process sends the Framework process stuff via fwProcess.StandardInput.WriteLine(Serialize(<some stuff>));

This also works when the .NET Framework process is replaced with a .NET Core process.

So it seems like the 256-character limit doesn't apply when redirecting stdout/stdin, but if someone can dig up the definitive proof/docs explaining this, I would appreciate it. If there is still a limit (excluding the OutOfMemory case), but it's 1.1 billion characters, I would like to know. I'd also like to know if this is platform dependent (I'm on Windows 10).

If it helps, this is the code that I'm running.

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);
pushkin
  • 9,575
  • 15
  • 51
  • 95
  • specifically https://stackoverflow.com/a/5558123/1704458 – T.S. Feb 07 '20 at 00:43
  • I'm using win10 running .Net Core 3.1. Look through Console.In, there is a private property _maxCharsPerBuffer = 16384. Not sure if this is varied across platform, Microsoft may state a "least" size in document? – Louis Go Feb 07 '20 at 00:51
  • @T.S. Well, my question is different from that one. I'm not asking if there is a max length. I'm asking why I don't have the limit that's documented – pushkin Feb 07 '20 at 01:17
  • @T.S. Well, I guess the body of the question is a bit different from the title. I suppose it's more related to mine than I thought – pushkin Feb 07 '20 at 01:18
  • 1
    Related github issue? https://github.com/dotnet/runtime/issues/29029 – Jeremy Lakeman Feb 07 '20 at 03:32
  • @T.S. The specific answer you linked to doesn't seem to apply in my case. I can send over 60 thousand characters over. maybe has something to do with the fact that I'm redirecting stdin/stdout – pushkin Feb 07 '20 at 18:26

1 Answers1

2

Paraphrasing from 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.

The default buffer size used when opening Console.In is now 4096 (source)

The documentation is open source, and available here if you would like to submit an issue or pull request.

When redirecting StandardOut/StandardIn, this limit does not apply. From here:

The limit is how much memory you pass in.

pushkin
  • 9,575
  • 15
  • 51
  • 95
Jeremy Lakeman
  • 9,515
  • 25
  • 29
  • thanks, this is helpful. I've updated my question to note that sending data between two net processes doesn't seem to have this limit. I can successfully read tens of thousands of chars from my .NET FW process. I'll search if there's a different limit in FW. (redirected stdin/stdout) – pushkin Feb 07 '20 at 15:28
  • As I quoted in my answer, this behaviour depends on reading from an interactive console. That's where the behaviour originates. I think that .net's `Console.ReadLine` should be changed to hide this OS implementation detail and keep reading until an actual new line is found. – Jeremy Lakeman Feb 08 '20 at 01:35