使用线程捕获进程输出

时间:2009-11-03 23:19:50

标签: java multithreading

我正在使用一个线程来捕获进程的流输出,然后将该流输出到eclipse控制台。我的问题是何时终止正在进行流输出的线程。

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();

我的问题是isProcessDone()函数中的内容。我基于此的示例使用了流的ready()函数,但我不清楚这是否适用于std :: err和std :: out的程序,但不能同时适用于两者。我也尝试过使用

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

但是线程在while循环有机会对流进行操作之前完成,输出就会丢失。

4 个答案:

答案 0 :(得分:7)

您需要使用Process.waitFor()等待流程完成。

此外,您需要同时使用stdout和stderr 以避免阻塞和可能的进程挂起。因此,您需要两个线程来读取这些流,并在流可用时继续读取。

有关详细信息,请参阅this Javaworld article,使用stdout / err获取StreamGobbler实现。

答案 1 :(得分:2)

您可以使用VerboseProcess中的jcabi-log(我是开发人员):

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

您需要的唯一依赖:

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

答案 2 :(得分:1)

您需要有两个主题。一个用于处理I / O而另一个用于等待进程完成(Process.waitFor())并设置一个标志,告诉I / O线程在耗尽数据时退出。

答案 3 :(得分:0)

您需要处理在单独的线程中读取输出,例如here