Lea la salida estándar del proceso antes de recibir una nueva línea

Estoy tratando de hacer algo que parece estar fuera del alcance del objeto System.Diagnostics.Process. Las respuestas aceptables pueden proponer un enfoque diferente siempre que utilice .net 4.5 / c # 5.

Mi programa está llamando a gdalwarp.exe para realizar procesos de larga ejecución en grandes archivos tiff. Galwarp.exe genera en este formato.

Creating output file that is 6014P x 4988L.  
Processing input file [FileName].tiff. 
Using band 4 of source image as alpha. 
Using band 4 of destination image as alpha.
0...10...20...30...40...50...60...70...80...90...100 - done.

La última línea fluye lentamente para indicar progreso. Me gustaría leer esa línea cada vez que cambie para poder mover una barra de progreso manteniendo informado al usuario.

Primero intenté leerProcess.StandardOutput pero no entrega datos hasta que se complete todo el proceso. Segundo intenté llamarProcess.BeginOutputReadLine() y conecta el eventoProcess.OutputDataReceived pero solo se dispara cuando se completa una línea.

Aquí está la llamada para ejecutar GDalWarp.exe.

    public static void ResizeTiff(string SourceFile, string DestinationFile, float ResolutionWidth, float ResolutionHeight, Guid ProcessId)
    {
        var directory = GDalBin;
        var exe = Path.Combine(directory, "gdalwarp.exe");
        var args = " -ts " + ResolutionWidth + " " + ResolutionHeight + " -r cubic -co \"TFW=YES\" \"" + SourceFile + "\" \"" + DestinationFile + "\"";
        ExecuteProcess(exe, args, null, directory, 0, null, true, true, 0);
    }

Aquí está mi código de trabajo en una función estática que solo lee la salida después de que finaliza el proceso.

public static string ExecuteProcess(string FilePath, string Args, string Input, string WorkingDir, int WaitTime = 0, Dictionary<string, string> EnviroVariables = null, bool Trace = false, bool ThrowError = true, int ValidExitCode = 0)
{
    var processInfo =
        "FilePath: " + FilePath + "\n" +
        (WaitTime > 0 ? "WaitTime: " + WaitTime.ToString() + " ms\n" : "") +
        (!string.IsNullOrEmpty(Args) ? "Args: " + Args + "\n" : "") +
        (!string.IsNullOrEmpty(Input) ? "Input: " + Input + "\n" : "") +
        (!string.IsNullOrEmpty(WorkingDir) ? "WorkingDir: " + WorkingDir + "\n" : "") +
        (EnviroVariables != null && EnviroVariables.Count > 0 ? "Environment Variables: " + string.Join(", ", EnviroVariables.Select(a => a.Key + "=" + a.Value)) + "\n" : "");

    if(Trace)
        Log.Debug("Running external process with the following parameters:\n" + processInfo);

    var startInfo = (string.IsNullOrEmpty(Args))
        ? new ProcessStartInfo(FilePath)
        : new ProcessStartInfo(FilePath, Args);

    if (!string.IsNullOrEmpty(WorkingDir))
        startInfo.WorkingDirectory = WorkingDir;

    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardError = true;
    startInfo.CreateNoWindow = true;

    if (!string.IsNullOrEmpty(Input))
        startInfo.RedirectStandardInput = true;

    if (EnviroVariables != null)
        foreach (KeyValuePair<String, String> entry in EnviroVariables)
            startInfo.EnvironmentVariables.Add(entry.Key, entry.Value);

    var process = new Process();
    process.StartInfo = startInfo;
    if (process.Start())
    {
        if (Input != null && Input != "")
        {
            process.StandardInput.Write(Input);
            process.StandardInput.Close();
        }
        var standardError = "";
        var standardOutput = "";
        int exitCode = 0;

        var errorReadThread = new Thread(new ThreadStart(() => { standardError = process.StandardError.ReadToEnd(); }));
        var outputReadTread = new Thread(new ThreadStart(() => { standardOutput = process.StandardOutput.ReadToEnd(); }));
        errorReadThread.Start();
        outputReadTread.Start();
        var sw = Stopwatch.StartNew();
        bool timedOut = false;
        try
        {
            while (errorReadThread.IsAlive || outputReadTread.IsAlive)
            {
                Thread.Sleep(50);
                if (WaitTime > 0 && sw.ElapsedMilliseconds > WaitTime)
                {
                    if (errorReadThread.IsAlive) errorReadThread.Abort();
                    if (outputReadTread.IsAlive) outputReadTread.Abort();
                    timedOut = true;
                    break;
                }
            }

            if (!process.HasExited)
                process.Kill();

            if (timedOut)
                throw new TimeoutException("Timeout occurred during execution of an external process.\n" + processInfo + "Standard Output: " + standardOutput + "\nStandard Error: " + standardError);

            exitCode = process.ExitCode;
        }
        finally
        {
            sw.Stop();
            process.Close();
            process.Dispose();
        }

        if (ThrowError && exitCode != ValidExitCode)
            throw new Exception("An error was returned from the execution of an external process.\n" + processInfo + "Exit Code: " + exitCode + "\nStandard Output: " + standardOutput + "\nStandard Error: " + standardError);

        if (Trace)
            Log.Debug("Process Exited with the following values:\nExit Code: {0}\nStandard Output: {1}\nStandard Error: {2}", exitCode, standardOutput, standardError);

        return standardOutput;
    }
    else return null;
}

¿Alguien puede ayudarme a leer esta salida en tiempo real?

Respuestas a la pregunta(1)

Su respuesta a la pregunta