While running an external script, I want to read the ErrorStream and OutputStream of this script both simultaneously and separately and then process them further. Therefore, I start a Thread
for one of the streams. Unfortunately, the Process
doesn't seem to waitFor
the Thread
to be terminated, but return after the non-threaded stream has no further input.
In a nutshell, here is what I am doing:
ProcessBuilder pb = new ProcessBuilder(script);
final Process p = pb.start();
new Thread(new Runnable() {
public void run() {
BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
...read lines and process them...
}
}).start();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
...read lines and process them...
int exitValue = p.waitFor();
p.getOutputStream().close();
return exitValue;
Is there any possibility to waitFor
the Thread
to be terminated?
You can use Thread.join(...)
to wait for a Thread
to finish. Note that the call throws InterruptedException
if the current thread receives an interrupt before the thread you are waiting for finishes.
Here's general code for doing what you want to do. In this case there is both input and output: I am piping someFile
into the process and piping the output to System.out
. Files.copy()
and ByteStreams.copy()
are just Guava convenience methods to hook up an InputStream
to an OutputStream
. We then wait for the command to finish.
final Process pr = Runtime.getRuntime().exec(cmd);
new Thread() {
public void run() {
try (OutputStream stdin = pr.getOutputStream()) {
Files.copy(someFile, stdin);
}
catch (IOException e) { e.printStackTrace(); }
}
}.start();
new Thread() {
public void run() {
try (InputStream stdout = pr.getInputStream()) {
ByteStreams.copy(stdout, System.out);
}
catch (IOException e) { e.printStackTrace(); }
}
}.start();
int exitVal = pr.waitFor();
if( exitVal == 0 )
System.out.println("Command succeeded!");
else
System.out.println("Exited with error code " + exitVal);
A more verbose version if you are running prior to Java 7 with the try-with-resources block:
final Process pr = Runtime.getRuntime().exec(cmd);
new Thread() {
public void run() {
OutputStream stdin = null;
try {
Files.copy(someFile, stdin = pr.getOutputStream());
}
catch (IOException e) { e.printStackTrace(); }
finally {
if( stdin != null ) {
try { stdin.close(); }
catch (IOException e) { e.printStackTrace(); }
}
}
}
}.start();
new Thread() {
public void run() {
InputStream stdout = null;
try {
ByteStreams.copy(stdout = pr.getInputStream(), System.out);
}
catch (IOException e) { e.printStackTrace(); }
finally {
if( stdout != null ) {
try { stdout.close(); }
catch (IOException e) { e.printStackTrace(); }
}
}
}
}.start();
int exitVal = pr.waitFor();
if( exitVal == 0 )
System.out.println("Command succeeded!");
else
System.out.println("Exited with error code " + exitVal);