32

擬似コードでは、これが私がしていることです:

Process proc = runtime.exec(command);
processOutputStreamInThread(proc.getInputStream());
processOutputStreamInThread(proc.getErrorStream());
proc.waitFor()

ただし、processOutputStreamInThread出力が表示されない場合と表示される場合があります。大まかに言って、このメソッドはBufferedInputStreamコマンドの出力を作成し、それをロガーに送信します。

私が見ているものに基づいて、とによってcommand供給されるストリームにすべての出力をダンプする必要はないので、ストリームを空にする必要はないと推測しています。getInputStream()getErrorStream()

私の試験の結果は次の質問です:

(1)java.lang.ProcesswaitFor()では、実行されたプログラムの出力が返される前に読み取られている必要がありますか?

ドキュメントには次のように記載されています。

Processこのオブジェクトによって表されるプロセスが終了するまで、必要に応じて現在のスレッドを待機させます。サブプロセスがすでに終了している場合、このメソッドはすぐに戻ります。サブプロセスがまだ終了していない場合、呼び出し元のスレッドはサブプロセスが終了するまでブロックされます。

(2)ストリームはどのような条件下で提供されgetInputStreamgetErrorStream閉じる必要がありますか、および/または自動的に閉じられますか?

ドキュメントには次のように記載されています。

サブプロセスのエラーストリームを取得します。ストリームは、このProcessオブジェクトによって表されるプロセスのエラー出力ストリームからパイプされたデータを取得します。

実装上の注意:入力ストリームをバッファリングすることをお勧めします。

あるユーザーは、自分でストリームを閉じなければならなかったと報告していますが、少なくとも一部の時間は、そうしようとするとストリームがすでに閉じられていることを示す例外が発生します。

編集:に変更さgetOutputStreamgetInputStream、現在は上にあります。

解決策:問題は、場合によっては、出力ストリームの処理に使用されるスレッドが、非常に短期間のプロセスが完了するまで実行されず、入力ストリームからデータが得られないことでした。 waitFor実行されたプログラムの出力を待つことはしませんでした。むしろ、出力が収集される前に、プログラムが実行されて終了しました。

スレッドを使用したのは、標準エラーと標準出力でどれだけの出力が得られるかわからないためです。どちらか一方だけがデータを使用できる場合は、どちらか一方をブロックせずに、両方を同時に処理できるようにしたかったのです。しかし、私のスレッドは実行されたプログラムの出力を一貫して読み取ることができないため、それは解決策ではありません。

私の最終的なコードは次のようになりました。

ProcessBuilder pb = new ProcessBuilder(cmdargs);
pb.redirectErrorStream(true);
Process proc = pb.start();
processOutputStream(proc.getInputStream());
proc.waitFor()
4

2 に答える 2

29

外部プロセスがその に何かを期待しているstdin場合は、getOutputStream. そうでなければ、あなたはwaitFor永遠になります。

JavaWorldのWhen Runtime.exec() will not の記事では、exec メソッドのさまざまな落とし穴とその回避方法について説明しています。

私の経験から、子プロセスの STDOUT と STDERR を (それらが EOF になるまで) 消費してからブロックする方がよいでしょうwaitFor。この時点で、長く待つ必要がないことを願っています。

カレブの質問に対する答え。通常の状態では、ストリームを閉じるべきではありwaitingForませんが、何らかの理由でタイムアウトがないため、出力でエラー状態が発生し、子のストリームを処理したくない場合は、これらのストリームを閉じる必要がある場合があります。さらに出力します。ただし、STDOUTまたはSTDERRパイプが反対側で閉じられたときに子プログラムが終了(クラッシュ)するかどうかは、完全にその子の実装次第です。ただし、ほとんどのシェル プログラムは、このような条件下で終了します。

waitForただし、意味のあるタイムアウトがあり、Process監視を中止することにしたときにリソースをクリーンアップする方法が文書化されていることを本当に望んでいます。

于 2010-01-27T23:33:34.000 に答える
2

これは少し直感に反すると思いますが、次のようになります。

getOutputStreamサブプロセスの出力ストリームを取得します。ストリームへの出力は、このProcessオブジェクトによって表されるプロセスの標準入力ストリームにパイプされます。実装上の注意:出力ストリームをバッファリングすることをお勧めします。戻り値:サブプロセスの通常の入力に接続された出力ストリーム。

これをメインプロセスからのこの出力ストリームとして読み取り、サブプロセスの標準入力にアタッチされているため、getOutputStream()。write()に書き込むと、実際にはstdinに書き込みます。

.getInputStream()を使用しますか?

戻り値:サブプロセスの通常の出力に接続された入力ストリーム。

Process.Waitfor()に関しては、APIドキュメントは次のように述べています。

このProcessオブジェクトによって表されるプロセスが終了するまで、必要に応じて現在のスレッドを待機させます。サブプロセスがすでに終了している場合、このメソッドはすぐに戻ります。サブプロセスがまだ終了していない場合、呼び出し元のスレッドはサブプロセスが終了するまでブロックされます。

これが呼び出されたスレッドは、プロセスの実行が終了するまでブロックされます。他のスレッドによっては、この段階で出力を処理している場合もあれば、スレッドが戻る前に終了している場合もあります。

于 2010-01-27T22:41:30.720 に答える