我从 .NET 应用程序运行 exe 并尝试将标准重定向到流读取器。问题是当我这样做时
我的进程.exe >> out.txt
out.txt 接近 14mb。当我执行命令行版本时,它非常快,但是当我从我的 csharp 应用程序运行该过程时,它非常慢,因为我相信默认的流读取器每 4096 个字节刷新一次。
有没有办法更改 Process 对象的默认流阅读器?
我从 .NET 应用程序运行 exe 并尝试将标准重定向到流读取器。问题是当我这样做时
我的进程.exe >> out.txt
out.txt 接近 14mb。当我执行命令行版本时,它非常快,但是当我从我的 csharp 应用程序运行该过程时,它非常慢,因为我相信默认的流读取器每 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();
}
编辑:刚刚意识到我在回答错误的问题。在我的情况下,标准输出缓冲区已满,WaitForExit() 永远阻塞,因为还没有从缓冲区读取。因此,如果您有这个问题,那么这里有一个解决方案。;)
这是我使用 C# 的第一天,所以请理解这可能不是最好的解决方案,并且可能并不总是有效。但它适用于我测试过的 2 倍。;) 这是同步的,只需在 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();
是的,这差不多。有一个缓冲区存储进程输出,在常见的 CRT 实现中通常在 1 到 4KB 之间。一个小细节:该缓冲区位于您启动的进程中,而不是 .NET 程序中。
当您重定向到一个文件时,没有什么特别需要发生的,CRT 直接写入它。但是,如果您重定向到您的 .NET 程序,则输出会从缓冲区进入管道。然后将线程切换到您的程序,以便您可以清空管道。来回好700次。
是的,不快。不过很容易修复,在您正在运行的程序中调用 setvbuf() 以增加 stdout 和 stderr 输出缓冲区的大小。再说一次,这需要拥有该程序的源代码。
预计会出现问题:也许您应该使用 cmd.exe /c 来重定向到文件,然后读取文件。
Process 类直接公开标准输出流,因此您应该能够以您喜欢的任何速度阅读它。最好分小块阅读它并避免调用 ReadToEnd。
例如:
using(StreamReader sr = new StreamReader(myProcess.StandardOutput))
{
string line;
while((line = sr.ReadLine()) != null)
{
// do something with line
}
}
这对我有用:
var sb = new StringBuilder();
while (!proc.StandardOutput.EndOfStream)
{
sb.Append(proc.StandardOutput.ReadToEnd());
proc.StandardOutput.DiscardBufferedData();
}