2010-01-18 100 views
6

我正在使用C#並無法理解如何從子進程異步讀取標準輸出。我想要做的是創建一個執行應用程序的子進程,然後在文本框中顯示從進程的stdout接收到的任何內容。我需要立即看到子進程中的每個輸出字符,並且不能等待一行完成,因此我認爲事件並不適合我的目的。你能告訴我一個完美的方法嗎?C#異步讀取子進程的stdout

我嘗試過撥打電話Process.StandardOutput.BaseStream.BeginRead()並將回撥功能傳遞給它,但在此回撥功能中,我收到來自Process.StandardOutput.BaseStream.EndRead()的例外。

我的代碼看起來像這樣(子進程是一個腳本引擎 - 簡稱「SE」 - 用於驗證外部設備的功能腳本按順序執行,每個腳本需要SE應用程序的一個實例)

private bool startScript() 
{ 
    // Starts the currently indexed script 

    if (null != scriptList) 
    { 

    if (0 == scriptList.Count || scriptListIndexer == scriptList.Count) 
    { 
     // If indexer equals list count then there are no active scripts in 
     // the list or the last active script in the list has just finished 
     return false;        // ## RETURN ## 
    } 
    if (ScriptExecutionState.RUNNING == scriptList[scriptListIndexer].executionState) 
    { 
     return false;        // ## RETURN ## 
    } 

    if (0 == SE_Path.Length) 
    { 
     return false;        // ## RETURN ## 
    } 

    SE_Process = new Process(); 
    SE_Process.StartInfo.FileName = SE_Path; 
    SE_Process.StartInfo.CreateNoWindow = true; 
    SE_Process.StartInfo.UseShellExecute = false; 
    SE_Process.StartInfo.RedirectStandardError = true; 
    SE_Process.StartInfo.RedirectStandardOutput = true; 
    SE_Process.EnableRaisingEvents = true; 
    SE_Process.StartInfo.Arguments = scriptList[scriptListIndexer].getParameterString(); 

    // Subscribe to process exit event 
    SE_Process.Exited += new EventHandler(SE_Process_Exited); 

    try 
    { 
     if (SE_Process.Start()) 
     { 
     // Do stuff 
     } 
     else 
     { 
     // Do stuff 
     } 
    } 
    catch (Exception exc) 
    { 
     // Do stuff 
    } 

    // Assign 'read_SE_StdOut()' as call-back for the event of stdout-data from SE 
    SE_Process.StandardOutput.BaseStream.BeginRead(SE_StdOutBuffer, 0, SE_BUFFERSIZE, read_SE_StdOut, null); 

    return true;          // ## RETURN ## 

    } 
    else 
    { 
    return false;          // ## RETURN ## 
    } 
} 

private void read_SE_StdOut(IAsyncResult result) 
{ 
    try 
    { 
    int bytesRead = SE_Process.StandardOutput.BaseStream.EndRead(result); // <-- Throws exceptions 

    if (0 != bytesRead) 
    { 
     // Write the received data in output textbox 
     ... 
    } 

    // Reset the callback 
    SE_Process.StandardOutput.BaseStream.BeginRead(SE_StdOutBuffer, 0, SE_BUFFERSIZE,  read_SE_StdOut, null); 
    } 
    catch (Exception exc) 
    { 
    // Do stuff 
    } 
} 

void SE_Process_Exited(object sender, EventArgs e) 
{ 

    // Keep track of whether or not the next script shall be started 
    bool continueSession = false; 

    switch (SE_Process.ExitCode) 
    { 
    case 0: // PASS 
    { 
     // Do stuff 
    } 

    ... 

    } 

    SE_Process.Dispose(); // TODO: Is it necessary to dispose of the process? 

    if (continueSession) 
    { 
    ts_incrementScriptListIndexer(); 

    if (scriptListIndexer == scriptList.Count) 
    { 
     // Last script has finished, reset the indexer and re-enable 
     // 'scriptListView' 
     ... 
    } 
    else 
    { 
     if (!startScript()) 
     { 
     // Do stuff 
     } 
    } 
    } 
    else 
    { 
    ts_resetScriptListIndexer(); 
    threadSafeEnableScriptListView(); 
    } 
} 

會發生什麼事是,一個SE過程完成後,我得到InvalidOperationException型,說

StandardOut沒有被重定向或 進程尚未啓動的一個例外。

從呼叫到SE_Process.StandardOutput.BaseStream.EndRead()。我不明白爲什麼,因爲我在每個新流程開始之前都設置了SE_Process.StartInfo.RedirectStandardOutput。在我看來,如果退出進程的標準輸出流在處理完成後調用我的read_SE_StdOut()函數,那麼這可能嗎?

謝謝您的閱讀!

+0

您可能會對[MedallionShell]庫(https://github.com/madelson/MedallionShell)庫感興趣,它簡化了處理io流,特別是異步操作 – ChaseMedallion 2014-08-29 23:41:35

回答

2

你得到的異常是正常的。一個BeginRead()調用永遠不會成功:最後一個,在進程終止後。如果您知道該過程已完成,您通常會避免再次撥打BeginRead(),以免發生異常。但是,你很少知道。趕上例外。或者使用BeginOutputReadLine()代替它,它會爲您抓到它。

我猜你也會重定向stderr並且該工具使用它來輸出「X」。在stderr標準輸出被緩衝並重定向後,無法保持同步輸出。

+0

我明白了,我只是處理異常。 關於人物的擾亂順序;還有X:es被標準輸出,所以我不認爲這解釋了爲什麼它們出現亂序。我會讓這個問題沒有得到答覆,因爲我最大的問題是輸出的顯示不正確(我認爲它可能與異常有關,但也許不是)。謝謝您的回答! – jokki 2010-01-19 09:46:28

+0

我收到的字符無序顯示的問題不再發生,我必須修復它意外:) 我已經刪除了上述問題的部分,並設置問題爲「回答」。 再次感謝! – jokki 2010-01-21 11:43:05