Analyser la sortie d’un processus mettant à jour une seule ligne de console

Salutations membres de stackoverflow,

dans un BackgroundWorker d’un frontal WPF, j’exécute sox (outil de traitement du son pour la console open source) dans un System.Diagnostics.Process . De la même manière, j’utilise plusieurs autres outils de ligne de commande et parsing leur sortie pour afficher les barres de progression dans mon interface.

Cela fonctionne bien pour les autres outils mais pas pour Sox car au lieu d’envoyer des nouvelles lignes à chaque étape de la progression, il met à jour une seule ligne sur la console en utilisant uniquement les retours chariots (\ r) et aucun saut de ligne (\ n). J’ai essayé les lectures asynchrones et synchrones sur process.StandardError .

Utilisation d’un process.ErrorDataReceived += (sender, args) => FadeAudioOutputHandler(clip, args); asynchrone.ErrorDataReceived process.ErrorDataReceived += (sender, args) => FadeAudioOutputHandler(clip, args); en combinaison avec process.BeginErrorReadLine(); ne produit aucune mise à jour de statut individuelle car, pour une raison quelconque, les retours à la ligne ne déclenchent pas ReadLine, même si la documentation MSDN le suggère. La sortie est crachée en un morceau à la fin du processus.

J’ai ensuite essayé le code suivant pour les lectures char par char sur le stream:

 char[] c; var line = new SsortingngBuilder(); 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.ToSsortingng()); 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]); } } 

Le code ci-dessus ne semble pas lire le stream en temps réel, mais bloquera la sortie pendant un moment. Ensuite, une petite quantité de spams se bloque et les blocages sont finalement bloqués à mi-chemin du processus.

Toute allusion à la bonne direction serait grandement appréciée!

MISE À JOUR avec (sloppy?) Solution:

Cela m’a rendu fou parce que rien de ce que j’ai essayé du côté C # ne semblait avoir d’effet sur les résultats. Ma mise en œuvre initiale, avant de la modifier 15 fois et de créer de nouvelles dépendances, était correcte.

Le problème concerne uniquement sox et RedirectStandardError. J’ai découvert cela après avoir récupéré le code source de sox et construit ma propre version. Tout d’abord, j’ai supprimé toute la sortie de sox, à l’exception des choses qui m’intéressaient vraiment, puis de la transformer en lignes complètes suivies d’un retour à la ligne \n . J’ai supposé que cela réglerait mes problèmes. Eh bien, ça n’a pas été le cas. Je ne connais pas assez de c ++ pour savoir pourquoi, mais ils semblent avoir été tempérés par la manière dont stdio écrit dans ce stream, comment il est mis en mémoire tampon ou utilisé de telle manière que le lecteur de stream du côté c # ne soit pas vidé jusqu’au paramètre par défaut. La mémoire tampon de 4096 octets est saturée. J’ai confirmé cela en ajoutant chaque ligne à au moins 4096 octets. En conclusion, tout ce que je devais faire était de vider manuellement stderr dans sox.c après chaque appel fprintf fprintf(stderr, ...) dans display_status(...) :

 fflush(stderr); 

Bien que, je ne suis pas sûr que ce soit nulle part près d’une solution élégante.

Merci à Erik Diesortingch pour sa réponse qui m’a fait regarder la question sous un angle différent.

La situation que vous décrivez est un problème connu – pour une solution incluant le code source, voir http://www.codeproject.com/KB/threads/ReadProcessStdoutStderr.aspx

Il résout les deux problèmes (impasse et problème avec \n ) …

J’ai eu à faire face à un problème similaire avec un outil de construction sur mesure dans Visual Studio. J’ai constaté que l’utilisation d’un regex et l’parsing dans le même thread que la lecture pose un problème et que le traitement de la sortie s’arrête. Je me suis retrouvé avec une solution grand public standard dans laquelle vous lisiez les lignes de la sortie et les colliez dans une queue. Ensuite, supprimez la queue et traitez-la sur un autre thread. Je ne peux pas offrir de code source, mais ce site propose des ressources fantastiques: http://www.albahari.com/threading/part2.aspx

C’est un peu compliqué, mais vous pourriez peut-être diriger la sortie du processus peu coopératif vers un processus qui ne fait que traiter les entrées, insérer des sauts de ligne et écrire dans la sortie standard … Donc, en termes de (très) pseudo -code:

 StartProcess("sox | littleguythatIwrote") ReadStandardOutTheWayYouAleadyAre() 

Peut-être que cela ne fait que déplacer les poteaux de but (je suis beaucoup plus familier avec les std in / out / err dans le monde NIX), mais c’est une façon différente de regarder le problème, de toute façon.