【问题标题】:C# Read stdout of child process asynchronouslyC#异步读取子进程的stdout
【发布时间】:2010-01-18 11:57:35
【问题描述】:

我正在使用 C#,但无法理解如何从子进程异步读取 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();
  }
}

发生的情况是,在一个 SE 进程完成后,我得到一个类型为 InvalidOperationException 的异常

StandardOut 尚未重定向或 该过程尚未开始。

来自对SE_Process.StandardOutput.BaseStream.EndRead()的调用。我不明白为什么,因为我在每个新进程开始之前都设置了SE_Process.StartInfo.RedirectStandardOutput。在我看来,就好像一个已退出进程的标准输出流在处理该进程后调用了我的 read_SE_StdOut() 函数,这可能吗?

感谢您的阅读!

【问题讨论】:

  • 您可能对MedallionShell 库感兴趣,它简化了进程io 流的处理,尤其是异步操作

标签: c#


【解决方案1】:

你得到的异常是正常的。一个BeginRead() 调用永远不会成功:最后一个,就在进程终止之后。如果您知道该过程已完成,您通常会避免再次调用BeginRead(),这样您就不会遇到异常。然而,你很少知道。只需捕获异常。或者改用BeginOutputReadLine(),它会为你捕捉到它。

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

【讨论】:

  • 我明白了,那我就处理这个异常。关于乱序的人物; X:es 也被放在标准输出上,所以我认为这不能解释为什么它们出现乱序。我会让这个问题没有答案,因为我最大的问题是输出显示不正确(我认为它可能与异常有关,但也许不是)。谢谢你的回答!
  • 我不再出现接收字符显示混乱的问题,我一定是不小心修复了它:) 我已经删除了上面问题的那部分并将问题设置为“已回答”。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多