C#异步读取子进程的stdout

我正在使用C#,并且无法理解如何从子进程异步读取stdout 。 我想要做的是创建一个执行应用程序的子进程,然后在文本框中显示从该进程’stdout收到的任何内容。 我需要立即查看子进程中的每个输出字符,并且不能等待一行完成,因此我不认为Process.OutputDataReceived事件适合我的目的。 你能告诉我一个理智的方法吗?

我已经尝试调用Process.StandardOutput.BaseStream.BeginRead()并向其传递回调函数,但在此回调函数中,我从Process.StandardOutput.BaseStream.EndRead()收到exception。

我的代码看起来像这样(子进程是一个脚本引擎 – 缩写为“SE” – 用于validation外部设备的function。脚本按顺序执行,每个脚本需要一个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的exception

StandardOut尚未重定向或进程尚未开始。

从调用SE_Process.StandardOutput.BaseStream.EndRead() 。 我不明白为什么,因为我在每个新进程开始之前设置了SE_Process.StartInfo.RedirectStandardOutput 。 在我看来,在处理完进程后,退出进程的stdout流调用了我的read_SE_StdOut()函数,这可能吗?

谢谢你的阅读!

你获得的例外是正常的。 一个BeginRead()调用永远不会成功:最后一个,就在进程终止之后。 如果您知道该过程已完成,则通常不会再次调用BeginRead() ,因此您不会获得exception。 但是,你很少知道。 抓住exception。 或者使用BeginOutputReadLine()代替它,它会为你捕获它。

我猜你也重定向stderr并且该工具使用它来输出“X”。 在缓冲和重定向后,无法在stderrstdout上保持同步输出