Grüße Stackoverflow-Mitglieder,
in einem BackgroundWorker eines WPF Frontends führe ich sox (Open-Source-Konsolen-Tonbearbeitungsprogramm) in einer System.Diagnostics.Process
. Auf die gleiche Weise verwende ich verschiedene andere Kommandozeilentools und analysiere deren Ausgabe, um Fortschrittsbalken in meinem Frontend zu erzeugen.
Dies funktioniert gut für die anderen Tools, aber nicht für Sox, denn anstatt für jeden Fortschrittsschritt neue Zeilen zu erzeugen, wird nur eine einzige Zeile auf der Konsole aktualisiert, indem nur Zeilenumbrüche verwendet werden ( \r ) und keine Zeilenvorschübe ( \n ). Ich habe sowohl asynchrone als auch synchrone Lesevorgänge auf process.StandardError
.
Verwendung von async process.ErrorDataReceived += (sender, args) => FadeAudioOutputHandler(clip, args);
in Verbindung mit process.BeginErrorReadLine();
erzeugt keine individuellen Statusaktualisierungen, weil aus irgendeinem Grund die Zeilenumbrüche nicht ReadLine auslösen, obwohl die MSDN-Dokumente dass dies der Fall sein sollte. Die Ausgabe wird in einem Stück ausgegeben, wenn der Prozess beendet ist.
Ich habe dann den folgenden Code für synchrone char-by-char-Lesevorgänge auf dem Stream ausprobiert:
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]);
}
}
Der obige Code scheint den Stream nicht in Echtzeit zu lesen, sondern hält die Ausgabe für eine Weile auf. Dann spammt er einen kleinen Brocken und blockiert schließlich auf halbem Weg durch den Prozess.
Für jeden Hinweis in die richtige Richtung wären wir Ihnen sehr dankbar!
UPDATE mit (schlampiger?) Lösung:
Das hat mich verrückt gemacht, weil nichts, was ich auf der C#-Seite versucht habe, irgendeine Wirkung auf die Ergebnisse zu haben schien. Meine ursprüngliche Implementierung, bevor Sie es 15 Mal ändern und neue Abhängigkeiten einführen, war in Ordnung.
Das Problem ist mit sox und RedirectStandardError allein. Ich entdeckte das, nachdem ich den sox-Quellcode genommen und meine eigene Version gebaut hatte. Zuerst habe ich die gesamte Ausgabe von sox entfernt, mit Ausnahme der Dinge, die mich wirklich interessierten, und dann die Ausgabe in volle Zeilen gefolgt von einem Zeilenumbruch geändert \n
. Ich nahm an, dass dies meine Probleme lösen würde. Nun, das hat es nicht. Ich weiß nicht genug C++, um tatsächlich herauszufinden, warum, aber sie scheinen mit, wie stdio schreibt, dass Stream, wie es gepuffert oder tun es in einer solchen speziellen Weise, dass der Streamreader auf der c#-Seite nicht gespült wird, bis die Standard 4096 Byte Puffer voll ist temperiert haben. Ich habe das bestätigt, indem ich jede Zeile auf mindestens 4096 Byte aufgefüllt habe. Alles, was ich also tun musste, war, stderr in sox.c nach jeder Zeile manuell zu spülen. fprintf(stderr, ...)
hereinrufen display_status(...)
:
fflush(stderr);
Allerdings bin ich mir nicht sicher, ob dies auch nur annähernd eine elegante Lösung ist.
Vielen Dank an Erik Dietrich für seine Antwort, die mich veranlasst hat, die Sache aus einem anderen Blickwinkel zu betrachten.