我正在使用C#,并且无法理解如何从子进程异步读取stdout.我想要做的是创建一个子进程来执行一个应用程序,然后在文本框中显示从该进程'stdout收到的任何内容.我需要立即查看子进程中的每个输出字符,并且不能等待一行完成,因此我认为该Process.OutputDataReceived事件不符合我的目的.你能告诉我一个理智的方法吗?
我已经尝试调用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();
}
}
Run Code Online (Sandbox Code Playgroud)
什么情况是,后一个SE过程完成后,我得到的类型的异常InvalidOperationException,说
StandardOut尚未重定向或进程尚未开始.
从电话到SE_Process.StandardOutput.BaseStream.EndRead().我不明白为什么,因为我已经SE_Process.StartInfo.RedirectStandardOutput在每个新流程开始之前设置了.在我看来,好像被退出进程的stdout流read_SE_StdOut()在进程被处理后调用了我的函数,这可能吗?
谢谢你的阅读!
您遇到的异常是正常的。一次BeginRead()调用永远不会成功:最后一次调用,就在进程终止之后。如果您知道该过程已完成,通常会避免BeginRead()再次调用,这样就不会出现异常。然而,你很少知道。只需捕获异常即可。或者改用BeginOutputReadLine()它,它会帮你抓住它。
我猜您还重定向了stderr并且该工具使用它来输出“X”。在缓冲和重定向后,无法保持stderr和stdout上的输出同步。
| 归档时间: |
|
| 查看次数: |
3096 次 |
| 最近记录: |