C#System.Diagnostics.Process重定向标准输出以获取大量数据

我从.NET应用程序运行exe并尝试将标准重定向到streamreader。 问题是,当我这样做

myprocess.exe >> out.txt

out.txt接近14mb。 当我执行命令行版本时,它非常快,但是当我从我的csharp应用程序运行该过程时,它非常慢,因为我相信默认的streamreader每4096字节刷新一次。

有没有办法更改Process对象的默认流读取器?

我没有尝试过,但看起来异步方法可能会提供更好的性能。 而不是使用process.StandardOutput ,请尝试使用此方法:

 Process process = Process .Start(new ProcessStartInfo("a.exe"){RedirectStandardOutput = true}); if (process != null) { process.OutputDataReceived += ((sender, e) => { string consoleLine = e.Data; //handle data }); process.BeginOutputReadLine(); } 

是的,那是对的。 存储过程输出的缓冲区通常在公共CRT实现中介于1到4KB之间。 一个小细节:缓冲区位于您启动的进程中,而不是.NET程序中。

当您重定向到文件时,没有什么特别需要发生,CRT直接写入它。 但是,如果您重定向到.NET程序,则输出将从缓冲区转移到管道中。 然后将线程切换到您的程序,以便您可以清空管道。 来回好700次。

是的,不快。 虽然很容易修复,但是在正在运行的程序中调用setvbuf()来增加stdout和stderr输出缓冲区大小。 然后,这需要具有该程序的源代码。

预见到一个问题:也许您应该使用cmd.exe / c来重定向到文件,然后读取该文件。

编辑:刚刚意识到我正在回答错误的问题。 在我的情况下,stdout缓冲区已满,WaitForExit()永远阻塞,因为还没有从缓冲区读取。 所以,如果你有这个问题,那么这是一个解决方案。 ;)

这是我使用C#的第一天,所以请理解这可能不是最好的解决方案,并且可能并不总是有效。 但它在2x我的测试中工作。 ;)这是同步的,只需在WaitForExit()之前开始将重定向的stdout / stderr写入文件。 这样WaitForExit()就不会阻止等待stdout缓冲区被清空。

  string str_MyProg = "my.exe"; string str_CommandArgs = " arg1 arg2"' System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo(str_MyProg, str_CommandArgs); procStartInfo.RedirectStandardError = true; procStartInfo.RedirectStandardOutput = true; // Set true to redirect the process stdout to the Process.StandardOutput StreamReader procStartInfo.UseShellExecute = false; procStartInfo.CreateNoWindow = true; // Do not create the black window // Create a process, assign its ProcessStartInfo and start it System.Diagnostics.Process myProcess = new System.Diagnostics.Process(); myProcess.StartInfo = procStartInfo; myProcess.Start(); // Dump the output to the log file string stdOut = myProcess.StandardOutput.ReadToEnd(); StreamWriter logFile = new StreamWriter("output.txt" ); logFile.Write(stdOut); logFile.Close(); myProcess.WaitForExit(); 

Process类直接公开stdout流,因此您应该能够以任何您喜欢的速度读取它。 最好以小块读取它,避免调用ReadToEnd。

例如:

 using(StreamReader sr = new StreamReader(myProcess.StandardOutput)) { string line; while((line = sr.ReadLine()) != null) { // do something with line } }