Javaで外部プロセスの出力/エラーストリームを処理する標準的な方法は、2つの余分なスレッドを使用して、プロセスがブロックされないように、出力ストリームとエラーストリームが生成されます。余分なスレッドを使わずにJavaでプロセスの出力/エラーを個別に処理する
次に、次はどうなりますか?
public static void main(String[] args) throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder(args);
Process process = processBuilder.start();
InputStream outputStream = null, errorStream = null;
ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream();
try {
outputStream = process.getInputStream();
errorStream = process.getErrorStream();
byte[] tmp = new byte[1024];
while (true) {
int outputBytes = readAvailablOnce(outputStream, outputBuffer, tmp);
int errorBytes = readAvailablOnce(errorStream, errorBuffer, tmp);
if (outputBytes == 0 && errorBytes == 0) {
try {
process.exitValue();
break;
} catch (IllegalThreadStateException e) {
// keep on looping
}
}
}
readAvailableAll(outputStream, outputBuffer, tmp);
readAvailableAll(errorStream, errorBuffer, tmp);
} finally {
closeQuietly(outputStream);
closeQuietly(errorStream);
}
System.out.println(outputBuffer.toString("ASCII"));
System.err.println(errorBuffer.toString("ASCII"));
System.err.println("exit code: " + process.exitValue());
}
private static void closeQuietly(InputStream in) {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// ignored
}
}
}
private static int readAvailablOnce(
InputStream inputStream, OutputStream outputStream, byte[] buffer)
throws IOException {
int bytesRead = 0;
if (inputStream.available() > 0) {
bytesRead = inputStream.read(buffer);
outputStream.write(buffer, 0, bytesRead);
}
return bytesRead;
}
private static void readAvailableAll(
InputStream inputStream, OutputStream outputStream, byte[] buffer)
throws IOException {
if (inputStream.available() > 0) {
int bytesRead = 0;
while ((bytesRead = inputStream.read(buffer)) >= 0) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
これは、私が試したいくつかの例(「dir」、「ps aux」など)で実際にうまく動作します。
また、BuffersやCharsetDecodersで多かれ少なかれ複雑な作業をやり始めない限り、出力を行単位で簡単に扱うことができないという欠点があります。
しかし、出力が許容できないほど大きいものはありません(ただし、使用する前に出力全体をバッファリングする必要はありません)。
私は1.5と1.6のJVM(Windows XPとLinux)のみを試しました。
また、このコードは、プロセスの最終出力ビットが読み込み(InputStream.available()> 0)にすぐに利用できることを前提にしています。
誰でも、このコードに何が(または何か)間違っている(または良いアイデアがある)のは知っているでしょうか?
あなたは[codereview](http://codereview.stackexchange.com/)について知っていますか?ベータ版ですが、うまく機能しているようです。 –
私はしなかった!ありがとう。私は2つの余分なスレッドのアプローチは古典的な答えであり、それは正しく感じていないので、一般的なソリューションが実際にJavaで動作するかどうか(私の小さなテストを超えて)に興味があります。私は両方のツールでそれを持っていることが無礼でないなら、 "codereview"で提出するかもしれません。 – viphe