2009-09-07 17 views
32

corro ffmpeg como esto:Cómo obtener el resultado de un System.Diagnostics.Process?

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

... pero el problema es que la consola con ffmpeg aparece y desaparece de inmediato, por lo que no se puede obtener ninguna respuesta. Ni siquiera sé si el proceso se ejecutó correctamente.

Entonces, ¿cómo puedo ya sea:

  • Dile a la consola para permanecer abierto

  • Recuperar en el C# lo que la consola representada

Respuesta

48

Lo que hay que hacer es captura la secuencia de salida estándar:

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

Es posible que también deba hacer algo similar con StandardError. A continuación, puede hacer lo que desee con q.

Es un poco fastidioso, como descubrí en one of my questions

Como Jon Skeet ha señalado, no es inteligente en cuanto al rendimiento de usar la concatenación de cadenas como éste; en su lugar debe usar 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(); 
+4

cosas básicas derecha, pero no recomendaría construir la cadena así.Use un StringBuilder :) –

+0

gracias, se ve bien Voy a intentarlo en este momento – marcgg

+1

en realidad hay un error: StandardOut no ha sido redirigido o el proceso aún no ha comenzado. Estoy tratando de descubrir qué está pasando – marcgg

3

Sé que esta pregunta es viejo, pero voy a añadir a ella de todos modos.

Si todo lo que desea hacer es mostrar el resultado de un proceso de línea de comandos, y está generando el proceso desde una ventana de consola, solo necesita redirigir la entrada estándar (sí, sé que suena mal, pero trabajos).

Así:

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(); 

harían muy bien.

+0

No le agregó mucho, porque eso ya se mencionó en la respuesta aceptada. –

+0

No, no lo era. –

+16

¿Estoy borracho o el nombre de Michael Vasquez y, en realidad, la mayor parte del HTML en torno a su comentario, todo al revés? –

4

Para una respuesta más específica directamente relacionada con ffmpeg, pasar el comando "-report" a ffmpeg hará que se descargue un registro en el directorio actual con lo que se dijo en la pantalla del proceso.

‘-report’

Dump full command line and console output to a file named program-YYYYMMDD-HHMMSS.log in the current directory. This file can be useful for bug reports. It also implies -loglevel verbose.

Note: setting the environment variable FFREPORT to any value has the same effect.

De FFMpeg Documentation.

17

La respuesta de Lucas tiene una condición de carrera: si el proceso finaliza rápidamente, el ciclo while se deja (o nunca se ingresó), incluso si queda algo de salida, es posible que se pierda algunos datos. Para evitar eso, se debe hacer otro ReadToEnddespués de el proceso salió.

(Tenga en cuenta que en comparación con la versión anterior de mi respuesta, ya no puedo ver la necesidad de WaitForExit vez la bandera process.HasExited es cierto, por lo que este se reduce a :)

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()); 

    // ... 
} 
+0

Creo que el primer ejemplo crea una situación de punto muerto. Si el proceso escribe demasiada salida, bloqueará la espera de una oportunidad de escribir más salida. Esto no sucederá para la producción por debajo de un cierto umbral. Si bloquea, se cuelga para siempre. [Hasta que se cancele] – Cameron

+0

@Cameron: actualicé la respuesta y eliminé el primer fragmento de código. Además, en el segundo fragmento, no puedo ver la necesidad de 'WaitToExit' por más tiempo: una vez que se deja el ciclo while, significa que el proceso ha finalizado. Sin embargo, no estoy seguro acerca de su reclamo. Eso significa que, incluso en una situación en la que no está interesado en la salida de los procesos, siempre tendrá que agregar un tiempo: estructura de ReadToEnd para entrar en el código, quiere iniciar un proceso usando 'Process.Start' para asegurarse de que proceso no se detiene esperando en "espacio libre". – chiccodoro

+0

Verifiqué mi reclamo después de la publicación. Compruébalo y mira. – Cameron

Cuestiones relacionadas