2012-03-02 3 views
4

У меня проблема с чтением вывода одного процесса асинхронно в C#. Я нашел некоторые другие подобные вопросы на этом сайте, но они мне действительно не помогают. Вот что я делаю:Как читать для завершения процесса вывода асинхронно в C#?

  1. сделать новый процесс
  2. Set startinfo -filename, аргументы, CreateNoWindow (истина), UseShellExecute (ложь), RedirectStandardOutput (истина)
  3. Добавить обработчик события OutputDataReceived;
  4. Начальный процесс, BeginOutputReadLine, а затем WaitForExit().

Он отлично работает, но выход из запущенного процесса пишет несколько процентов (%), которые я хочу получить, но я не могу, так как мой код считывает построчно и проценты не отображаются.

Пример:

%0,%1...%100 
Finished. 

Мой выход:

%0 
Finished. 

Вот текущий код моей программы:

StringBuilder sBuilder = new StringBuilder(); 
static void proc_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    sBuilder.AppendLine(e.Data); 
} 

static void CommandExecutor() 
{ 
    Process process = new Process 
    { 
     StartInfo = new ProcessStartInfo 
     { 
      FileName = /*path of the program*/, 
      Arguments = /*arguments*/, 
      CreateNoWindow = true, 
      UseShellExecute = false, 
      WindowStyle = ProcessWindowStyle.Hidden, 
      RedirectStandardOutput = true 
     } 
    }; 

    process.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived); 

    process.Start(); 

    process.BeginOutputReadLine(); 

    process.WaitForExit(); 
} 
+0

Вы поставить точку останова на методе appenline, чтобы увидеть, сколько раз он попал? В консольном приложении проценты переписывают друг друга или непрерывны? –

+0

Проценты переписываются. Я поставлю точку останова, чтобы увидеть, что произойдет ... –

+0

Он попал восемь раз ... –

ответ

0

Что об использовании StreamReader на process.StandardOutput, и используя метод Read()? http://msdn.microsoft.com/fr-fr/library/system.io.streamreader.read(v=vs.80).aspx

+0

Я пробовал это, но он показывает результат, когда процесс заканчивается, и я не могу получить проценты ... –

+0

Можете ли вы предоставить код? – Onkelborg

+0

Я уже предоставил код. –

1

Есть несколько вещей, которые становятся на пути его ... приложение консоли, вероятно, с помощью «\ б» забоя перезаписать процент, его, возможно, не топя в поток стандартного вывода после каждой записи, и BeginOutputReadLine предположительно ждет конца строки перед предоставлением вам данных.

Посмотрите, как вы с чтением process.StandardOutput.BaseStream через BeginRead (этот код не является правильным асинхронной и «\ б» s будет нуждаться в обработке по-другому, если ваш положить прогресс в форме):

 while (true) 
     { 
      byte[] buffer = new byte[256]; 
      var ar = myProcess.StandardOutput.BaseStream.BeginRead(buffer, 0, 256, null, null); 
      ar.AsyncWaitHandle.WaitOne(); 
      var bytesRead = myProcess.StandardOutput.BaseStream.EndRead(ar); 
      if (bytesRead > 0) 
      { 
       Console.Write(Encoding.ASCII.GetString(buffer, 0, bytesRead)); 
      } 
      else 
      { 
       myProcess.WaitForExit(); 
       break; 
      } 
     } 
+0

Я посмотрю на это и попробую ... –

5

Кажется, что поток потока чтения асинхронно бит разбит - не все данные считываются до выхода процесса. Даже если вы звоните Process.WaitForExit(), и даже если вы тогда звоните Process.Close() (или Dispose()), вы все равно можете получить много данных впоследствии. См. http://alabaxblog.info/2013/06/redirectstandardoutput-beginoutputreadline-pattern-broken/ для полной записи, но решение в основном заключается в использовании синхронных методов. Чтобы избежать тупиковой ситуации, хотя, вы должны позвонить по одному из них в другом потоке:

using (var process = Process.Start(processInfo)) 
{ 
    // Read stderr synchronously (on another thread) 

    string errorText = null; 
    var stderrThread = new Thread(() => { errorText = process.StandardError.ReadToEnd(); }); 
    stderrThread.Start(); 

    // Read stdout synchronously (on this thread) 

    while (true) 
    { 
     var line = process.StandardOutput.ReadLine(); 
     if (line == null) 
      break; 

     // ... Do something with the line here ... 
    } 

    process.WaitForExit(); 
    stderrThread.Join(); 

    // ... Here you can do something with errorText ... 
} 
+1

спасибо, работал на меня. Глупый сломанный BeginOutputReadLine –

+0

@ EM0, ссылка кажется сломанной. – Chau

3

Process.WaitForExit() будет ждать, пока асинхронный выход/ошибка чтения поток завершенным. К сожалению, это не относится к перегрузке Process.WaitForExit (timeout). Это то, что класс процессов делает внутренне:

// ...

finally 
{ 
    if (processWaitHandle != null) 
    { 
     processWaitHandle.Close(); 
    } 
    if (this.output != null && milliseconds == -1) 
    { 
     this.output.WaitUtilEOF(); 
    } 
    if (this.error != null && milliseconds == -1) 
    { 
     this.error.WaitUtilEOF(); 
    } 
    this.ReleaseProcessHandle(safeProcessHandle); 
} 

... Так будет ждать асинхронной читает, только если не было тайм-аут! Чтобы исправить это, просто вызовите без параметров WaitForExit() после того, как WaitForExit (timeout) вернёт true:

// ...

if (process.WaitForExit(10 * 1000) && process.WaitForExit()) 
{ 
// Process'es OutputDataReceived/ErrorDataReceived callbacks will not be called again, EOF streams reached 
} 
else 
{ 
    throw new Exception("timeout"); 
} 

Для получения дополнительной информации прочитайте замечания здесь: http://msdn.microsoft.com/en-us/library/ty0d8k56%28v=vs.110%29

Смежные вопросы