解析来自更新单个控制台行的进程的输出 [英] Parse output from a process that updates a single console line

查看:91
本文介绍了解析来自更新单个控制台行的进程的输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问候stackoverflow成员,

Greetings stackoverflow members,

我运行 System.Diagnostics.Process 中的nofollow> sox (开源控制台声音处理工具)。同样,我使用其他几个命令行工具并解析它们的输出以在前端中填充进度条。

in a BackgroundWorker of a WPF Frontend i run sox (open source console sound processing tool) in a System.Diagnostics.Process. In that same way i use several other command line tools and parse their output to poulate progress bars in my frontend.

这对其他工具有效,但对Sox无效,因为它不会在每个进度步骤中添加新行,而是仅使用回车键(\r)和不使用换行符(\n)来更新控制台上的一行。我在 process.StandardError 上尝试了异步和同步读取。

This works fine for the other tools but not for Sox since instead of spamming new lines for each progress step, it updates a single line on the console by only using carriage returns (\r) and no line feeds (\n). I tried both asynchronous and synchronous reads on process.StandardError.

使用异步进程。 ErrorDataReceived + =(sender,args)=> FadeAudioOutputHandler(clip,args); process.BeginErrorReadLine(); 结合使用不会产生任何单独的状态更新,因为某种原因返回结果不会触发ReadLine,即使 MSDN文档建议这样做。

Using async process.ErrorDataReceived += (sender, args) => FadeAudioOutputHandler(clip, args); in combination with process.BeginErrorReadLine(); doesn't produce any individual status updates because for some reason the carriage returns do not trigger ReadLine, even though the MSDN docs suggest that it should. The output is spit out in one chunk when the process finishes.

然后,我尝试在流上逐字符读取以下同步char代码:

I then tried the following code for synchronous char by char reads on the stream:

char[] c;
var line = new StringBuilder();
while (process.StandardError.Peek() > -1)
{
    c = new char[1];
    process.StandardError.Read(c, 0, c.Length);
    if (c[0] == '\r')
    {
        var percentage = 0;
        var regex = new Regex(@"%\s([^\s]+)");
        var match = regex.Match(line.ToString());
        if (match.Success)
        {
            myProgressObject.ProgressType = ProgressType.FadingAudio
            //... some calculations omitted for brevity
            percentage = (int) Math.Round(result);
        }
        else
        {
            myProgressObject.ProgressType = ProgressType.UndefinedStep;
        }
        _backGroundWorker.ReportProgress(percentage, myProgressObject);
        line.Clear();
    }
    else
    {
        line.Append(c[0]);
    }
}

上面的代码似乎没有读取其中的流实时,但会暂停输出一段时间。然后它会散布一小块,最后在过程中途陷入僵局。

The above code does not seem to read the stream in realtime but will stall output for a while. Then it spams a small chunk and finally deadlocks half-way through the process.

任何朝着正确方向的提示将不胜感激!

Any hints towards the right direction would be greatly appreciated!

使用(草率?)解决方案进行更新:

这使我发疯,因为我在C#方面没有尝试事情似乎对结果没有任何影响。在更改15次并引入新的依赖关系之前,我的原始实现很好。

This drove me crazy because nothing i tried on the C# side of things seemed to have any effect on the results. My original implementation, before changing it 15 times and introducing new dependencies, was fine.

问题仅在于sox和RedirectStandardError。在找到sox源代码并构建自己的版本之后,我发现了这一点。首先,我完全除去了sox的所有输出,除了我真正感兴趣的东西,然后将输出更改为实线,然后换行 \n 。我以为这可以解决我的问题。好吧,不是。我不知道足够的C ++实际找出原因,但是他们似乎对stdio写入该流的方式,如何缓冲或以一种特殊的方式进行了调整,以至于在默认情况下,不会刷新c#端的流读取器4096字节缓冲区已满。我通过填充每一行至少4096字节来确认这一点。因此,总而言之,我要做的就是在 display_status()中的每个 fprintf(stderr,...)调用之后,在sox.c中手动刷新stderr。 ...)

The problem is with sox and RedirectStandardError alone. I discovered that after grabbing the sox source code and building my own version. First i removed all output of sox entirely except for the stuff i was really interested in and then changing the output to full lines followed by a newline \n . I assumed that this would fix my issues. Well, it didn't. I do not know enough c++ to actually find out why, but they seem to have tempered with how stdio writes to that stream, how it's buffered or do it in such a special way that the streamreader on the c# side is not flushed until the default 4096 byte buffer is full. I confirmed that by padding each line to at least 4096 byte. So in conclusion all i had to do was to manually flush stderr in sox.c after each fprintf(stderr, ...) call in display_status(...):

fflush(stderr);

尽管如此,我不确定这是否是一个优雅的解决方案。

Though, I'm not sure this is anywhere close to an elegant solution.

感谢埃里克·迪特里希(Erik Dietrich)的回答,这使我从另一个角度进行了研究。

Thanks to Erik Dietrich for his answer which made me look at this from a different angle.

推荐答案

您描述的情况是一个已知问题-有关包含源代码的解决方案,请参见 http: //www.codeproject.com/KB/threads/ReadProcessStdoutStderr.aspx

The situation you describe is a known problem - for a solution including source code see http://www.codeproject.com/KB/threads/ReadProcessStdoutStderr.aspx

它解决了两个问题(死锁和的问题\n )...

It solves both problems (deadlock and the problem with \n)...

这篇关于解析来自更新单个控制台行的进程的输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆