2012-03-02 89 views
4

我在C#中异步读取一个进程的输出时遇到了问题。 我在这个网站上发现了一些其他类似的问题,但他们并没有真正帮助我。 这里是我做的:如何读取以在C#中异步结束进程输出?

  1. 结交新工艺
  2. 设置的StartInfo -FileName,参数,CreateNoWindow(真),UseShellExecute(假),RedirectStandardOutput(真)
  3. 事件处理程序添加到OutputDataReceived;
  4. 启动进程,BeginOutputReadLine,然后WaitForExit()。

它工作正常,但启动过程的输出写入一些百分比(%),我想,但我不能,因为我的代码逐行地读取和百分比显示不出来。

例子:

%0,%1...%100 
Finished. 

我的输出:

%0 
Finished. 

这里是我的程序的当前代码:

StringBuilder sBuilder = new StringBuilder(); 
static void proc_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    sBuilder.AppendLine(e.Data); 
} 

static void CommandExecutor() 
{ 
    Process process = new Process 
    { 
     StartInfo = new ProcessStartInfo 
     { 
      FileName = /*path of the program*/, 
      Arguments = /*arguments*/, 
      CreateNoWindow = true, 
      UseShellExecute = false, 
      WindowStyle = ProcessWindowStyle.Hidden, 
      RedirectStandardOutput = true 
     } 
    }; 

    process.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived); 

    process.Start(); 

    process.BeginOutputReadLine(); 

    process.WaitForExit(); 
} 
+0

你已经把一个断点在appenline方法,看看它有多少次打?在控制台应用程序中,百分比是否覆盖彼此或连续? – 2012-03-02 12:17:40

+0

覆盖百分比。我会把一个断点看看会发生什么...... – 2012-03-02 12:25:14

+0

它被击中了八次...... – 2012-03-02 12:31:11

回答

1

有迹象表明,在它的方式得到一些东西...... 控制台应用程序可能是使用“\ B”退格覆盖的百分比,它也许不是以后每写刷新到标准输出流,并且BeginOutputReadLine可能在给你数据之前等待行结束。

见你上通过的BeginRead阅读process.StandardOutput.BaseStream(此代码是不正确的异步,如果“\ b”的旨意需要处理不同的形式把你的进度):

 while (true) 
     { 
      byte[] buffer = new byte[256]; 
      var ar = myProcess.StandardOutput.BaseStream.BeginRead(buffer, 0, 256, null, null); 
      ar.AsyncWaitHandle.WaitOne(); 
      var bytesRead = myProcess.StandardOutput.BaseStream.EndRead(ar); 
      if (bytesRead > 0) 
      { 
       Console.Write(Encoding.ASCII.GetString(buffer, 0, bytesRead)); 
      } 
      else 
      { 
       myProcess.WaitForExit(); 
       break; 
      } 
     } 
+0

我会看看这个,并尝试它... – 2012-03-02 13:16:23

5

似乎读取流异步输出有点失败 - 在进程退出之前并不是所有的数据都被读取。即使你打电话给Process.WaitForExit(),即使你打电话给Process.Close()(或Dispose()),你仍然可以获得大量的数据。请参阅http://alabaxblog.info/2013/06/redirectstandardoutput-beginoutputreadline-pattern-broken/进行全面的写作,但解决方案基本上是使用同步方法。为了避免死锁,但是,你必须调用其中的一个在另一个线程:

using (var process = Process.Start(processInfo)) 
{ 
    // Read stderr synchronously (on another thread) 

    string errorText = null; 
    var stderrThread = new Thread(() => { errorText = process.StandardError.ReadToEnd(); }); 
    stderrThread.Start(); 

    // Read stdout synchronously (on this thread) 

    while (true) 
    { 
     var line = process.StandardOutput.ReadLine(); 
     if (line == null) 
      break; 

     // ... Do something with the line here ... 
    } 

    process.WaitForExit(); 
    stderrThread.Join(); 

    // ... Here you can do something with errorText ... 
} 
+1

谢谢,为我工作。傻破了BeginOutputReadLine – 2015-07-09 01:11:57

+0

@ EM0,链接似乎中断。 – Chau 2017-07-26 14:18:20

3

Process.WaitForExit()将等到异步输出/错误流读取完成。不幸的是,对于Process.WaitForExit(超时)超载,这不是真的。这是Process类的内部所做的:

// ...

finally 
{ 
    if (processWaitHandle != null) 
    { 
     processWaitHandle.Close(); 
    } 
    if (this.output != null && milliseconds == -1) 
    { 
     this.output.WaitUtilEOF(); 
    } 
    if (this.error != null && milliseconds == -1) 
    { 
     this.error.WaitUtilEOF(); 
    } 
    this.ReleaseProcessHandle(safeProcessHandle); 
} 

...所以它会等待异步读取仅如果没有超时! 要修复它,只需在WaitForExit(超时)返回true后调用无参数WaitForExit():

// ...

if (process.WaitForExit(10 * 1000) && process.WaitForExit()) 
{ 
// Process'es OutputDataReceived/ErrorDataReceived callbacks will not be called again, EOF streams reached 
} 
else 
{ 
    throw new Exception("timeout"); 
} 

详情这里读评论:http://msdn.microsoft.com/en-us/library/ty0d8k56%28v=vs.110%29