2012-03-02 20 views
4

C#で1つのプロセスの出力を非同期に読み取る際に問題があります。 このサイトで他にも同様の質問がありましたが、本当に助けにはなりません。ここで は私が何をすべきかです:プロセス出力をC#で非同期で終了する方法

  1. は、新しいプロセスを作成します
  2. セット -FileName、引数、CreateNoWindow(真)、あるUseShellExecute(偽)、RedirectStandardOutput(真)
  3. OutputDataReceivedにイベントハンドラを追加しstartinfo。
  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

それは8回ヒットしました... –

答えて

0

何process.StandardOutput上のStreamReaderを使用する方法については、とRead()メソッドの使用 http://msdn.microsoft.com/fr-fr/library/system.io.streamreader.read(v=vs.80).aspx

+0

私はこれを試しましたが、プロセスが終了してパーセンテージを取得できない場合の出力を示します... –

+0

いくつかのコードを提供できますか? – Onkelborg

+0

私はすでにコードを提供しています。 –

1

それの邪魔になっているいくつかのこと... コンソールアプリはおそらく、すべての書き込み後には多分標準出力ストリームにフラッシュしない、割合を上書きするために「\ B」バックスペースを使用しているが、あります。 BeginOutputReadLineはおそらくデータを与える前に行末を待つでしょう。

あなたはBeginRead経由process.StandardOutput.BaseStreamを読んでの取得方法を参照してください(このコードは、非同期適切でないと場合は、「\ bの」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(タイムアウト)オーバーロードには当てはまりません。 ...

//

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

...だから非同期がタイムアウトがなかった場合にのみ、読み込みのために待機します:これは、Processクラスは、内部的に何をするかです! これを修正するには、WaitForExit(timeout)がtrueを返すと、パラメータなしWaitForExit()を呼び出します。

// ...詳細について

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

関連する問題