Process.standardoutput.ReadToEnd() всегда пуст?

Я запускаю консольное приложение, но когда я перенаправляю стандартный вывод, я всегда ничего не получаю!

Когда я не перенаправляю его и устанавливаю CreateNoWindow в false, я вижу все правильно в консоли, но когда я перенаправляю его, StandardOutput.ReadToEnd() всегда возвращает пустую строку.

        Process cproc = new Process();
        cproc.StartInfo.CreateNoWindow = true;
        cproc.StartInfo.FileName = Dest;
        cproc.StartInfo.RedirectStandardOutput = true;
        cproc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        cproc.StartInfo.UseShellExecute = false;
        cproc.EnableRaisingEvents = true;
        cproc.Start();
        cproc.Exited += new EventHandler(cproc_Exited);
        while(!stop)
        {
           result += cproc.StandardOutput.ReadToEnd();
        }

EventHandler cproc_exited просто устанавливает stop в true. Может кто-нибудь объяснить, почему result всегда string.Empty?

Ответ 1

Почему вы зацикливаетесь? Как только он будет прочитан до конца, он не сможет читать больше данных, не так ли?

Вы уверены, что текст фактически записывается в StandardOutput, а не StandardError?

(И да, очевидно, вы хотите установить RedirectStandardOutput как true, а не false. Я предположил, что это всего лишь случай, когда вы копируете неправильную версию своего кода.)

EDIT: Как я уже сказал в комментариях, вы должны читать стандартный вывод и стандартную ошибку в отдельных потоках. Не ждите, пока процесс не выйдет - это может привести к тупиковой ситуации, когда вы ожидаете завершения процесса, но процесс блокирует попытку записи в stderr/stdout, потому что вы не читали из буфера.

В качестве альтернативы вы можете подписаться на события OutputDataReceived и ErrorDataReceived, чтобы избежать использования дополнительных потоков.

Ответ 2

Лучший способ для этого - перенаправить вывод и ждать событий:

    // some of the flags are not needed
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.ErrorDialog = false;
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.RedirectStandardInput = true;
    process.StartInfo.RedirectStandardOutput = true;
    process.EnableRaisingEvents = true;
    process.OutputDataReceived += process_OutputDataReceived;
    process.ErrorDataReceived += process_OutputDataReceived;
    process.Exited += process_Exited;
    process.Start();
    process.BeginErrorReadLine();
    process.BeginOutputReadLine();

    void process_Exited(object sender, System.EventArgs e)
    {
        // do something when process terminates;
    }

    void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        // a line is writen to the out stream. you can use it like:
        string s = e.Data;
    }

    void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        // a line is writen to the out stream. you can use it like:
        string s = e.Data;
    }

Ответ 3

У вас есть перенаправление стандартного отключенного. Попробуйте изменить

cproc.StartInfo.RedirectStandardOutput = false;

в

cproc.StartInfo.RedirectStandardOutput = true;

Работает ли для вас следующий образец MSDN?

// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "Write500Lines.exe";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();

Ответ 4

Избавьтесь от цикла и переместите вызов на ReadToEnd на cproc_Exited.