Приветствую членов stackoverflow,
в BackgroundWorker интерфейса WPF. Я запускаю sox (инструмент обработки звука консоли с открытым исходным кодом) в System.Diagnostics.Process
.Таким же образом я использую несколько других инструментов командной строки и анализирую их выходные данные для разбивки индикаторов выполнения в моем веб-интерфейсе.
Это отлично работает для других инструментов, но не для Sox, так как вместо спама новые строки для каждого шага прогресса, он обновляет одну строку в консоли, используя только возврат каретки (\ r) и отсутствие перевода строки (\ n).Я пробовал как асинхронное, так и синхронное чтение на process.StandardError
.
Использование async process.ErrorDataReceived += (sender, args) => FadeAudioOutputHandler(clip, args);
в сочетании с process.BeginErrorReadLine();
не приводит к каким-либо отдельным обновлениям статуса, поскольку по какой-то причине возврат каретки не вызывает ReadLine, дажехотя документы MSDN предполагают, что так и должно быть.Когда процесс завершается, вывод выводится в один блок.
Затем я попробовал следующий код для синхронного 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]);
}
}
Приведенный выше код не выглядитчитать поток в реальном времени, но на некоторое время остановит вывод.Затем он спамит небольшую порцию и, наконец, заходит в тупик на полпути процесса.
Будем весьма благодарны за любые подсказки в правильном направлении!
ОБНОВЛЕНИЕ с (небрежным?) Решением:
Это сводило меня с ума, потому что ничто из того, что я пробовал на стороне C #, казалось, никак не влияло на результаты.Моя первоначальная реализация до 15 раз ее изменения и введения новых зависимостей была в порядке.
Проблема только в sox и RedirectStandardError.Я обнаружил это после получения исходного кода sox и создания собственной версии.Сначала я полностью удалил весь вывод sox, за исключением того, что мне действительно было интересно, а затем изменил вывод на полные строки, за которыми следовал перевод новой строки \n
.Я предполагал, что это решит мои проблемы.Ну, это не так.Я не знаю достаточно C ++, чтобы на самом деле выяснить, почему, но, похоже, они закалились с тем, как stdio пишет в этот поток, как он буферизуется или делают это таким особым образом, что потоковый читатель на стороне c # не сбрасывается до значения по умолчаниюБуфер 4096 байт заполнен.Я подтвердил это, дополнив каждую строку как минимум до 4096 байт.Итак, в заключение все, что мне нужно было сделать, это вручную очищать stderr в sox.c после каждого fprintf(stderr, ...)
вызова в display_status(...)
:
fflush(stderr);
Хотя я не уверен, что это где-то близко кэлегантное решение.
Спасибо Эрику Дитриху за ответ, который заставил меня взглянуть на это с другой стороны.