Правильный способ обработки стандартной ошибки и вывода из программы, когда появляется через класс процесса из C#?
-
30-09-2019 - |
Вопрос
Я прочитал документацию для Process.standardOutput, который имеет эту цитату:
Условие тупика может привести к тому, что родительский процесс вызовет p.waitforexit до p.standardoutput.readtoend, а дочерний процесс записывает достаточно текста, чтобы заполнить перенаправленный поток.
Так что мне интересно. Как правильный способ сделать это, если я также боюсь, что StandardError может быть заполнен в некоторых сценариях?
Должен ли я использовать цикл для альтернативного чтения из стандартного вывода и ошибок, чтобы избежать либо заполнения, либо этот простой код достаточно:
string error = proc.StandardError.ReadToEnd();
string output = proc.StandardOutput.ReadToEnd();
bool didFinish = proc.WaitForExit(60000);
Отредактировано после того, как некоторые ответы были опубликованы
Так это правильный подход?
var output = new StringBuilder();
proc.OutputDataReceived += (s, e) => output.Append(e.Data);
proc.BeginOutputReadLine();
string error = proc.StandardError.ReadToEnd();
bool didFinish = proc.WaitForExit(60000);
А потом я использую контент StringBuilder, только если процесс фактически завершился.
Это правильный подход тогда?
Решение
Ваш пример кода может вызвать ситуацию тупика, когда было что -то написано StandardOutput
и не для StandardError
. Анкет Самый следующий пример из документации, которую вы связали, так же сильно.
По сути, то, что я бы порекомендовал, использует асинхронные чтения на обоих потоках, чтобы заполнить буфер по мере написания потоков, а затем вызовут WaitForExit
.
Другие советы
Проблема возникает из -за того, что дочерний процесс записывает свой стандартный выход и стандартную ошибку в пару труб, которые получают конечный буфер у ОС. Если родитель не активно читает их обоих, то он может заполнить. Когда труба заполняется, любые последующие записи к ней блокируются.
В вашем примере вы читаете все StandardError
тогда все StandardOutput
. Анкет Это работает нормально, если дочерний процесс только записывает немного данных StandardError
и/или StandardOutput
. Анкет Это проблема, если дочерний процесс хочет написать много данных StandardOutput
. Анкет Пока родительский процесс ждет использования данных из StandardError
, дочерний процесс занят заполнением StandardOutput
буфер.
Самый безопасный способ - прочитать из стандартной и стандартной ошибки одновременно. Есть несколько способов сделать это:
- Породить отдельные потоки и позвонить
ReadToEnd
на каждой - Использовать
BeginRead
иEndRead
на одной ветке - Добавить обработчиков на
Process.ErrorDataReceived
иProcess.OutputDataReceived
События, затем позвонитеProcess.BeginErrorReadLine
иProcess.BeginOutputReadLine
.