如何在C#中异步读取结束进程输出?

Nik*_*kov 7 c# asynchronous process

我在C#中异步读取一个进程的输出时遇到问题.我在这个网站上发现了一些其他类似的问题,但它们对我没有帮助.这是我做的:

  1. 制作新流程
  2. 设置startinfo -FileName,Arguments,CreateNoWindow(true),UseShellExecute(false),RedirectStandardOutput(true)
  3. 将事件处理程序添加到OutputDataReceived;
  4. 启动进程,BeginOutputReadLine,然后是WaitForExit().

它工作正常,但启动过程的输出写了一些%我想得到的百分比(),但我不能,因为我的代码逐行读取,百分比没有显示.

例:

%0,%1...%100
Finished.
Run Code Online (Sandbox Code Playgroud)

我的输出:

%0
Finished. 
Run Code Online (Sandbox Code Playgroud)

这是我的程序的当前代码:

StringBuilder sBuilder = new StringBuilder();
static void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    sBuilder.AppendLine(e.Data);
}

static void CommandExecutor()
{
    Process process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = /*path of the program*/,
            Arguments = /*arguments*/,
            CreateNoWindow = true,
            UseShellExecute = false,
            WindowStyle = ProcessWindowStyle.Hidden,
            RedirectStandardOutput = true
        }
    };

    process.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);

    process.Start();

    process.BeginOutputReadLine();

    process.WaitForExit();
}
Run Code Online (Sandbox Code Playgroud)

EM0*_*EM0 7

似乎异步读取流输出有点破碎 - 在进程退出之前不会读取所有数据.即使你打电话Process.WaitForExit(),即使你打电话Process.Close()(或Dispose()),你仍然可以获得大量的数据.有关完整的说明,请参阅http://alabaxblog.info/2013/06/redirectstandardoutput-beginoutputreadline-pattern-broken/,但解决方案基本上是使用同步方法.但是,要避免死锁,您必须在另一个线程上调用其中一个:

using (var process = Process.Start(processInfo))
{
    // Read stderr synchronously (on another thread)

    string errorText = null;
    var stderrThread = new Thread(() => { errorText = process.StandardError.ReadToEnd(); });
    stderrThread.Start();

    // Read stdout synchronously (on this thread)

    while (true)
    {
        var line = process.StandardOutput.ReadLine();
        if (line == null)
            break;

        // ... Do something with the line here ...
    }

    process.WaitForExit();
    stderrThread.Join();

    // ... Here you can do something with errorText ...
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,为我工作.愚蠢的BeginOutputReadLine (3认同)
  • @EM0,链接似乎已损坏。 (2认同)

Sly*_*Sly 6

Process.WaitForExit()将一直等到异步输出/错误流读取完成.不幸的是,对于Process.WaitForExit(超时)重载,情况并非如此.这是Process类在内部执行的操作:

// ...

finally
{
    if (processWaitHandle != null)
    {
        processWaitHandle.Close();
    }
    if (this.output != null && milliseconds == -1)
    {
        this.output.WaitUtilEOF();
    }
    if (this.error != null && milliseconds == -1)
    {
        this.error.WaitUtilEOF();
    }
    this.ReleaseProcessHandle(safeProcessHandle);
}
Run Code Online (Sandbox Code Playgroud)

...所以只有在没有超时的情况下它才会等待异步读取!要修复它,只需在WaitForExit(timeout)返回true后调用无参数WaitForExit():

// ...

if (process.WaitForExit( 10 * 1000 ) && process.WaitForExit() )
{
 // Process'es OutputDataReceived / ErrorDataReceived callbacks will not be called again, EOF streams reached
}
else
{
   throw new Exception("timeout");
}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请阅读此处的评论:http://msdn.microsoft.com/en-us/library/ty0d8k56%28v=vs.110%29


Jul*_*ien 0

StreamReader使用onprocess.StandardOutput和使用方法怎么样Read()http://msdn.microsoft.com/fr-fr/library/system.io.streamreader.read(v=vs.80).aspx