问候计算器件,输出解析更新单个控制台线路
在WPF前端的一个BackgroundWorker我运行在一个System.Diagnostics.Process
sox(开源控制台声音处理工具)。以同样的方式,我使用其他几个命令行工具并解析它们的输出以在我的前端填充进度条。
这适用于其他工具,但不适用于Sox,因为它不是为每个进度步骤发送新行,而是通过仅使用回车符(\ r)和没有换行符(\ n)更新控制台上的一行)。我在process.StandardError
上尝试了异步和同步读取。
结合使用异步process.ErrorDataReceived += (sender, args) => FadeAudioOutputHandler(clip, args);
与process.BeginErrorReadLine();
不会产生任何的个人状态更新,因为某些原因,回车不触发的ReadLine,即使MSDN docs认为它应该。当过程完成时,输出会在一个块中吐出。
我然后通过炭尝试了同步炭以下代码读取的流:
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]);
}
}
上面的代码似乎不读取实时数据流,但将停止输出一会儿。然后它会传播一个小块,最终在整个过程中发生死锁。
任何提示朝着正确的方向将不胜感激!
更新与(不拘小节?)解决方案:
这让我抓狂,因为没有什么我想对事物的C#方似乎对结果产生任何影响。我最初的实现,在改变它15次并引入新的依赖之前,没有问题。
问题在于单独使用sox和RedirectStandardError。我发现在获取sox源代码并构建自己的版本之后。首先我完全删除了sox的所有输出,除了我真正感兴趣的东西,然后将输出更改为全行,然后换行符\n
。我认为这会解决我的问题。那么,它没有。我不知道足够的C++来找出原因,但他们似乎已经缓和了stdio如何写入该流,如何缓冲或以如此特殊的方式执行,以至于c#端的streamreader不会刷新到默认值4096字节缓冲区已满。我确认通过填充每行至少4096字节。所以在最后我所要做的就是手动冲水标准错误中sox.c每个fprintf(stderr, ...)
通话后display_status(...)
:
fflush(stderr);
虽然,我不知道这是任何接近一个完美的解决方案。
感谢Erik Dietrich的回答,这让我从不同的角度来看待这个问题。
关于sox的信息让我感到好奇,所以我做了一些调查。这可能是一个远射,但http://en.wikipedia.org/wiki/Setvbuf有有趣的可能性。它看起来像你可以通过文件句柄强制缓冲设置,而不是通过进程。这可以让你'重写'sox的默认行为,这样你就可以独立保存它的源代码,而不会在每次更新它们的东西时注定要手动更新。可能有一个托管的C#等价物,或者你可以只写一个调用一个微小的C实用程序。 –