一尘不染

Java ProcessBuilder:转发已启动进程的stdout和stderr,而不会阻塞主线程

java

我正在使用ProcessBuilder在Java中构建一个流程,如下所示:

ProcessBuilder pb = new ProcessBuilder()
        .command("somecommand", "arg1", "arg2")
        .redirectErrorStream(true);
Process p = pb.start();

InputStream stdOut = p.getInputStream();

现在,我的问题如下:我想捕获通过该进程的stdout/stderr进行的操作并将其System.out异步重定向。我希望该过程及其输出重定向在后台运行。到目前为止,我发现这样做的唯一方法是手动产生一个新的线程,该线程将不断读取stdOut并调用适当的write()方法System.out

new Thread(new Runnable(){
    public void run(){
        byte[] buffer = new byte[8192];
        int len = -1;
        while((len = stdOut.read(buffer)) > 0){
            System.out.write(buffer, 0, len);
        }
    }
}).start();

虽然这种方法行得通,但感觉有点脏。最重要的是,它为我提供了另外一个线程来正确管理和终止。有什么更好的方法吗?


阅读 736

收藏
2020-03-07

共1个答案

一尘不染

在Java 6或更早版本中,唯一的办法是使用所谓的StreamGobbler(开始创建):

StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "ERROR");

// any output?
StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), "OUTPUT");

// start gobblers
outputGobbler.start();
errorGobbler.start();

private class StreamGobbler extends Thread {
    InputStream is;
    String type;

    private StreamGobbler(InputStream is, String type) {
        this.is = is;
        this.type = type;
    }

    @Override
    public void run() {
        try {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null)
                System.out.println(type + "> " + line);
        }
        catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

对于Java 7,请参阅Evgeniy Dorofeev的答案。

2020-03-07