web-dev-qa-db-fra.com

Comment obtenir la sortie d'un System.Diagnostics.Process?

Je lance ffmpeg comme ceci:

System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo = new System.Diagnostics.ProcessStartInfo(ffmpegPath, myParams);
p.Start();
p.WaitForExit();

... mais le problème est que la console avec ffmpeg apparaît et disparaît tout de suite, donc je ne peux obtenir aucun retour. Je ne sais même pas si le processus s'est déroulé correctement.

Alors, comment puis-je:

  • Dites à la console de rester ouverte

  • Récupérer en C # ce que la console affiche

36
marcgg

Ce que vous devez faire est de capturer le flux de sortie standard:

p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
// instead of p.WaitForExit(), do
string q = "";
while ( ! p.HasExited ) {
    q += p.StandardOutput.ReadToEnd();
}

Vous devrez peut-être également faire quelque chose de similaire avec StandardError. Vous pouvez alors faire ce que vous voulez avec q.

C'est un peu capricieux, comme je l'ai découvert dans ne de mes questions

Comme l'a souligné Jon Skeet, il n'est pas intelligent en termes de performances d'utiliser la concaténation de chaînes comme celle-ci; vous devez plutôt utiliser un StringBuilder :

p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
// instead of p.WaitForExit(), do
StringBuilder q = new StringBuilder();
while ( ! p.HasExited ) {
    q.Append(p.StandardOutput.ReadToEnd());
}
string r = q.ToString();
53
Lucas Jones

La réponse de Lucas a une condition de concurrence: si le processus se termine rapidement, la boucle while est laissée (ou jamais entrée) même s'il reste une sortie, c'est-à-dire que vous risquez de manquer certaines données. Pour éviter cela, un autre ReadToEnd doit être fait après le processus est sorti.

(Notez que par rapport à l'ancienne version de ma réponse, je ne vois plus le besoin de WaitForExit une fois le process.HasExited le drapeau est vrai, donc cela se résume à :)

using (var process = Process.Start(startInfo))
{
    var standardOutput = new StringBuilder();

    // read chunk-wise while process is running.
    while (!process.HasExited)
    {
        standardOutput.Append(process.StandardOutput.ReadToEnd());
    }

    // make sure not to miss out on any remaindings.
    standardOutput.Append(process.StandardOutput.ReadToEnd());

    // ...
}
20
chiccodoro

Pour une réponse plus spécifique directement liée à ffmpeg, le passage de la commande "-report" dans ffmpeg lui fera vider un journal dans le répertoire courant avec ce qui a été dit dans l'affichage du processus.

'-rapport'

Vider la ligne de commande complète et la sortie de la console dans un fichier nommé program-YYYYMMDD-HHMMSS.log dans le répertoire en cours. Ce fichier peut être utile pour les rapports de bogues. Cela implique également -loglevel verbose.

Remarque: définir la variable d'environnement FFREPORT sur n'importe quelle valeur a le même effet.

De Documentation FFMpeg .

4
Ben

Je sais que cette question est ancienne, mais j'y ajouterai quand même.

Si tout ce que vous souhaitez faire est d'afficher la sortie d'un processus de ligne de commande et que vous générez le processus à partir d'une fenêtre de console, vous n'avez qu'à rediriger l'entrée standard (oui, je sais que cela sonne mal, mais cela fonctionne).

Alors:

System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo = new System.Diagnostics.ProcessStartInfo(ffmpegPath, myParams);
p.UseShellExecute = false;
p.RedirectStandardInput = true;
p.Start();
p.WaitForExit();

Ferait très bien.

3
Michael Vasquez