2012-03-02 41 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