Java で外部プロセスを起動する際は ProcessBuilder クラスを使いますが、
たまに処理が戻ってこない場合があります。
そんな場合に原因として考えられるのは、標準出力または標準エラー出力にバッファが溜まってしまっているという理由です。
例えば以下のコードの場合、標準エラー出力のバッファがいっぱいになっていた場合は
proc.getInputStream() から処理が返って来なくなります。
String[] cmds = {"./foo.sh"};
ProcessBuilder pb = new ProcessBuilder(cmds);
Process proc = pb.start();
String str;
BufferedReader brstd = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while((str = brstd.readLine()) != null) {
trace(str);
}
brstd.close();
とはいえ、以下のようなコードにすると、今度は標準出力のバッファが溜まってしまった場合に
proc.getErrorStream() から処理が返って来なくなります。
String[] cmds = {"./foo.sh"};
ProcessBuilder pb = new ProcessBuilder(cmds);
Process proc = pb.start();
String str;
BufferedReader brerr = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
while((str = brerr.readLine()) != null) {
trace(str);
}
brerr.close();
BufferedReader brstd = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while((str = brstd.readLine()) != null) {
trace(str);
}
brstd.close();
標準出力とエラー出力が混ざってもOKという場合であれば、
redirectErrorStream が有効かと思います。
String[] cmds = {"./foo.sh"};
ProcessBuilder pb = new ProcessBuilder(cmds);
Process proc = pb.start();
// 標準出力と標準エラー出力をMIX
pb.redirectErrorStream(true);
String str;
BufferedReader brstd = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while((str = brstd.readLine()) != null) {
trace(str);
}
brstd.close();
これで、 proc.getInputStream() から処理が返って来なくなることはなくなります。
どうしても標準出力と標準エラー出力を分けなければいけない場合は、
片方を別スレッドで処理すればなんとかなります。
(あまり美しくないですが・・・)
String[] cmds = {"./foo.sh"};
ProcessBuilder pb = new ProcessBuilder(cmds);
final Process proc = pb.start();
//エラー出力は別スレッドで吐き出す
Thread th = new Thread(new Runnable() {
@Override
public void run() {
String str;
BufferedReader brerr = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
try {
while((str = brerr.readLine()) != null) {
trace(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
brerr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
th.start();
String str;
BufferedReader brstd = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while((str = brstd.readLine()) != null) {
trace(str);
}
brstd.close();