首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ProcessBuilder:在不阻塞主线程的情况下转发已启动进程的标准输出和标准错误

ProcessBuilder:在不阻塞主线程的情况下转发已启动进程的标准输出和标准错误
EN

Stack Overflow用户
提问于 2013-01-05 05:46:09
回答 12查看 119.9K关注 0票数 100

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

代码语言:javascript
运行
复制
ProcessBuilder pb = new ProcessBuilder()
        .command("somecommand", "arg1", "arg2")
        .redirectErrorStream(true);
Process p = pb.start();

InputStream stdOut = p.getInputStream();

现在我的问题如下:我希望捕获该进程的标准输出和/或标准错误,并将其异步重定向到System.out。我希望进程及其输出重定向在后台运行。到目前为止,我找到的唯一方法是手动生成一个新线程,该线程将不断地从stdOut读取数据,然后调用System.out的适当write()方法。

代码语言:javascript
运行
复制
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();

虽然这种方法行得通,但感觉有点脏。最重要的是,它给了我另一个线程来管理和正确终止。有没有更好的方法来做到这一点?

EN

回答 12

Stack Overflow用户

回答已采纳

发布于 2013-01-05 05:50:57

对于Java7和更高版本的,请参阅Evgeniy Dorofeev的answer

对于Java6和更早版本的,请创建并使用StreamGobbler

代码语言:javascript
运行
复制
StreamGobbler errorGobbler = 
  new StreamGobbler(p.getErrorStream(), "ERROR");

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

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

..。

代码语言:javascript
运行
复制
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();
        }
    }
}
票数 73
EN

Stack Overflow用户

发布于 2013-01-05 10:54:23

使用ProcessBuilder.inheritIO,它将子进程标准I/O的源和目标设置为与当前Java进程的源和目标相同。

代码语言:javascript
运行
复制
Process p = new ProcessBuilder().inheritIO().command("command1").start();

如果Java 7不是一个选项

代码语言:javascript
运行
复制
public static void main(String[] args) throws Exception {
    Process p = Runtime.getRuntime().exec("cmd /c dir");
    inheritIO(p.getInputStream(), System.out);
    inheritIO(p.getErrorStream(), System.err);

}

private static void inheritIO(final InputStream src, final PrintStream dest) {
    new Thread(new Runnable() {
        public void run() {
            Scanner sc = new Scanner(src);
            while (sc.hasNextLine()) {
                dest.println(sc.nextLine());
            }
        }
    }).start();
}

线程将在子进程结束时自动终止,因为src将EOF。

票数 158
EN

Stack Overflow用户

发布于 2015-10-28 16:59:07

使用Java8 lambda的灵活解决方案,允许您提供一个处理输出的Consumer (例如,记录)逐行记录。run()是一个没有抛出检查异常的一行程序。作为实现Runnable的替代方案,它也可以像其他答案所建议的那样扩展Thread

代码语言:javascript
运行
复制
class StreamGobbler implements Runnable {
    private InputStream inputStream;
    private Consumer<String> consumeInputLine;

    public StreamGobbler(InputStream inputStream, Consumer<String> consumeInputLine) {
        this.inputStream = inputStream;
        this.consumeInputLine = consumeInputLine;
    }

    public void run() {
        new BufferedReader(new InputStreamReader(inputStream)).lines().forEach(consumeInputLine);
    }
}

然后,您可以像这样使用它:

代码语言:javascript
运行
复制
public void runProcessWithGobblers() throws IOException, InterruptedException {
    Process p = new ProcessBuilder("...").start();
    Logger logger = LoggerFactory.getLogger(getClass());

    StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), System.out::println);
    StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), logger::error);

    new Thread(outputGobbler).start();
    new Thread(errorGobbler).start();
    p.waitFor();
}

在这里,logger将输出流重定向到System.out,并在错误级别记录错误流。

票数 21
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14165517

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档