我正在使用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()
函數,那麼這可能嗎?
謝謝您的閱讀!
您可能會對[MedallionShell]庫(https://github.com/madelson/MedallionShell)庫感興趣,它簡化了處理io流,特別是異步操作 – ChaseMedallion 2014-08-29 23:41:35