Adrian Park
Adrian Park

Reputation: 109

Using a thread to capture process output

I am using a thread to capture stream output from a process, and then outputting that stream to the eclipse console. The question I have is when to terminate the thread that is doing the stream output.

Thread t = new Thread(new Runnable(){
        private boolean isProcessDone(Process p)
        {
            //not sure what to do here
        }
        public void run()
        {
            Process p = Runtime.getRuntime().exec("executable with output");
            BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
            BufferedReader error = new BufferedReader (new InputStreamReader(p.getErrorStream()));
            while ( !isProcessDone(p) ) {
                String line;
                if( (line = input.readLine()) != null )
                {
                    System.out.println(line);
                }
                if( (line = error.readLine()) != null )
                {
                    System.out.println(line);
                }
            }
            input.close();  
            error.close();      
        }
    });
    t.start();

My question is what belongs in the isProcessDone() function. The example I am basing this off of uses the stream's ready() function, but I am unclear whether this will work for programs that either std::err and std::out, but not both. I also tried using

try{
    p.exitValue();
    return true;
}catch(IllegalThreadStateException e){}
return false;

but then the thread finishes before the while loop has a chance to act on the streams, and the output is lost.

Upvotes: 3

Views: 7758

Answers (4)

yegor256
yegor256

Reputation: 105083

You can use VerboseProcess from jcabi-log (I'm a developer):

String name = new VerboseProcess(
  new ProcessBuilder("executable with output")
).stdout();

The only dependency you need:

<dependency>
  <groupId>com.jcabi</groupId>
  <artifactId>jcabi-log</artifactId>
  <version>0.7.5</version>
</dependency>

Upvotes: 2

objects
objects

Reputation: 8677

You need to process reading the output in a separate thread, theres an example here

Upvotes: 0

Brian Agnew
Brian Agnew

Reputation: 272307

You need to use Process.waitFor() to wait for process completion.

Additionally, you need to consume stdout and stderr concurrently in order to avoid blocking and a possible process hang. Consequently you need two threads to read these streams, and to continue reading whilst the streams are available.

See this Javaworld article for more info and a StreamGobbler implementation to consume the stdout/err.

Upvotes: 8

Jim Garrison
Jim Garrison

Reputation: 86774

You will need to have two threads. One to handle the I/O and another to wait for process completion (Process.waitFor()) and set a flag telling the I/O thread to quit when it exhausts the data.

Upvotes: 1

Related Questions