简体   繁体   English

解析更新单个控制台行的进程的输出

[英]Parse output from a process that updates a single console line

Greetings stackoverflow members, 问候stackoverflow成员,

in a BackgroundWorker of a WPF Frontend i run sox (open source console sound processing tool) in a System.Diagnostics.Process . 在WPF Frontend的BackgroundWorker中,我在System.Diagnostics.Process运行sox (开源控制台声音处理工具)。 In that same way i use several other command line tools and parse their output to poulate progress bars in my frontend. 以同样的方式,我使用其他几个命令行工具并解析他们的输出以在我的前端poulate进度条。

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). 这适用于其他工具但不适用于Sox,因为它不是为每个进度步骤发送新行,而是通过仅使用回车符(\\ r)和没有换行符(\\ n)更新控制台上的单行。 I tried both asynchronous and synchronous reads on process.StandardError . 我在process.StandardError上尝试了异步和同步读取。

Using async process.ErrorDataReceived += (sender, args) => FadeAudioOutputHandler(clip, args); 使用async process.ErrorDataReceived += (sender, args) => FadeAudioOutputHandler(clip, args); in combination with process.BeginErrorReadLine(); process.BeginErrorReadLine();结合使用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. 不会产生任何单独的状态更新,因为由于某种原因,回车不会触发ReadLine,即使MSDN文档建议它应该。 The output is spit out in one chunk when the process finishes. 当进程完成时,输出将在一个块中吐出。

I then tried the following code for synchronous char by char reads on the stream: 然后,我通过对流的char读取尝试了以下代码用于同步char:

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! 任何有关正确方向的提示都将不胜感激!

UPDATE with (sloppy?) solution: 更新(草率?)解决方案:

This drove me crazy because nothing i tried on the C# side of things seemed to have any effect on the results. 这让我抓狂,因为我在C#方面尝试的东西似乎对结果没有任何影响。 My original implementation, before changing it 15 times and introducing new dependencies, was fine. 我最初的实现,在更改它15次并引入新的依赖项之前,很好。

The problem is with sox and RedirectStandardError alone. 问题出在sox和RedirectStandardError上。 I discovered that after grabbing the sox source code and building my own version. 我发现在获取sox源代码并构建自己的版本之后。 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 . 首先我完全删除了sox的所有输出,除了我真正感兴趣的东西,然后将输出更改为实线后跟换行符\\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. 我不知道足够的c ++实际找出原因,但是他们似乎已经调整了stdio如何写入该流,如何缓冲它或以如此特殊的方式执行它,使得c#端的流读取器不会刷新,直到默认4096字节缓冲区已满。 I confirmed that by padding each line to at least 4096 byte. 我确认通过将每行填充到至少4096字节。 So in conclusion all i had to do was to manually flush stderr in sox.c after each fprintf(stderr, ...) call in display_status(...) : 因此,总而言之,我所要做的就是在display_status(...)每个fprintf(stderr, ...)调用之后手动刷新sox.c中的fprintf(stderr, ...)

fflush(stderr);

Though, I'm not sure this is anywhere close to an elegant solution. 虽然,我不确定这是否接近优雅的解决方案。

Thanks to Erik Dietrich for his answer which made me look at this from a different angle. 感谢Erik Dietrich的回答让我从不同角度看待这个问题。

The situation you describe is a known problem - for a solution including source code see http://www.codeproject.com/KB/threads/ReadProcessStdoutStderr.aspx 您描述的情况是一个已知问题 - 对于包含源代码的解决方案,请参阅http://www.codeproject.com/KB/threads/ReadProcessStdoutStderr.aspx

It solves both problems (deadlock and the problem with \\n )... 它解决了两个问题(死锁和\\n的问题)......

I've had to deal with a similar issue with a bespoke build tool in visual studio. 我不得不在visual studio中使用定制的构建工具处理类似的问题。 I found that using a regex and doing the parsing in the same thread as the reading is a problem and the output processing grinds to a halt. 我发现使用正则表达式并在与读取相同的线程中进行解析是一个问题,输出处理将停止。 I ended up with a standard consumer producer solution where you read lines from the output and stick them onto a Queue. 我最终得到了一个标准的消费者生产者解决方案,您可以从输出中读取行并将它们粘贴到队列中。 Then have the queue be dequeued and processed on some other thread. 然后让队列出队并在其他线程上处理。 I can't offer source code but this site has some fantastic resources: http://www.albahari.com/threading/part2.aspx 我不能提供源代码,但这个网站有一些很棒的资源: http//www.albahari.com/threading/part2.aspx

It's a little kludgy, but perhaps you could pipe the output of the uncooperative process to a process that does nothing but process input by characters, insert line feeds, and write to to standard out... So, in terms of (very) pseudo-code: 它有点kludgy,但也许您可以将不合作进程的输出传递给一个进程,该进程除了处理字符输入,插入换行符和写入标准输出之外什么都不做......所以,就(非常)伪而言-码:

StartProcess("sox | littleguythatIwrote")
ReadStandardOutTheWayYouAleadyAre()

Could be that just moves the goalposts (I'm a lot more familiar with std in/out/err in the NIX world), but it's a different way to look at the problem, anyway. 可能只是移动球门柱(我对NIX世界中的std in / out / err更熟悉),但无论如何,这是一种不同的方式来看问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM