简体   繁体   English

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

[英]C# System.Diagnostics.Process redirecting Standard Out for large amounts of data

I running an exe from a .NET app and trying to redirect standard out to a streamreader.我从 .NET 应用程序运行 exe 并尝试将标准重定向到流阅读器。 The problem is that when I do问题是当我做

myprocess.exe >> out.txt myprocess.exe >> out.txt

out.txt is close to 14mb. out.txt 接近 14mb。 When I do the command line version it is very fast but when I run the process from my csharp app it is excruciatingly slow because I believe the default streamreader flushes every 4096 bytes.当我执行命令行版本时,它非常快,但是当我从我的 csharp 应用程序运行该进程时,它非常慢,因为我相信默认的流读取器每 4096 字节刷新一次。

Is there a way to change the default stream reader for the Process object?有没有办法更改 Process 对象的默认流读取器?

I haven't tried, but it looks like the asynchronous methods may offer better performance.我还没有尝试过,但看起来异步方法可能会提供更好的性能。 Instead of using process.StandardOutput , try this method instead:而不是使用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();
}

Edit: Just realized I'm answering the wrong question.编辑:刚刚意识到我在回答错误的问题。 In my case the stdout buffer was full and WaitForExit() was blocking forever, because nothing was reading from the buffer yet.就我而言,stdout 缓冲区已满,WaitForExit() 永远阻塞,因为尚未从缓冲区读取任何内容。 So if you have THAT problem, then here's a solution.所以如果你有那个问题,那么这里有一个解决方案。 ;) ;)

This is my first day with C# so please understand that this might not be the best solution, and might not always work.这是我使用 C# 的第一天,所以请理解这可能不是最好的解决方案,并且可能并不总是有效。 But it works in the 2x I've tested it.但它在我测试过的 2x 中有效。 ;) This is synchronous, just start start writing the redirected stdout/stderr to the file before you WaitForExit(). ;) 这是同步的,只需在 WaitForExit() 之前开始将重定向的 stdout/stderr 写入文件。 This way WaitForExit() won't block waiting for the stdout buffer to be emptied.这样 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();          

Yes, that's about right.是的,这是正确的。 There is a buffer that stores the process output, usually between 1 and 4KB in the common CRT implementations.一个缓冲器,其存储在所述公共CRT实现的过程输出,通常为1和4KB之间。 One small detail: that buffer is located in the process you start, not the .NET program.一个小细节:该缓冲区位于您启动的进程中,而不是 .NET 程序中。

Nothing very special needs to happen when you redirect to a file, the CRT directly writes it.当你重定向到一个文件时,没有什么特别需要发生的,CRT 直接写入它。 But if you redirect to your .NET program then output goes from the buffer into a pipe.但是如果你重定向到你的 .NET 程序,那么输出就会从缓冲区进入管道。 Which then takes a thread switch to your program so you can empty the pipe.然后将线程切换到您的程序,以便您可以清空管道。 Back and forth a good 700 times.来回好700次。

Yes, not fast.是的,不快。 Easily fixed though, call setvbuf() in the program you are running to increase the stdout and stderr output buffer sizes.不过很容易修复,在您正在运行的程序中调用 setvbuf() 以增加 stdout 和 stderr 输出缓冲区大小。 Then again, that takes having the source code of that program.再说一次,这需要拥有该程序的源代码。

Anticipating a problem with that: maybe you ought to use cmd.exe /c to get the redirection to a file, then read the file.预计会出现问题:也许您应该使用 cmd.exe /c 来重定向到一个文件,然后读取该文件。

The Process class exposes the stdout stream directly, so you should be able to read it at whatever pace you like. Process 类直接公开 stdout 流,因此您应该能够以您喜欢的任何速度阅读它。 It's probably best to read it in small chunks and avoid calling ReadToEnd.最好以小块读取它并避免调用 ReadToEnd。

For example:例如:

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

This worked out for me:这对我有用:

            var sb = new StringBuilder();
            while (!proc.StandardOutput.EndOfStream)
            {
                sb.Append(proc.StandardOutput.ReadToEnd());
                proc.StandardOutput.DiscardBufferedData();
            }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM