当前位置: 首页 > 面试题库 >

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

游高杰
2023-03-14
问题内容

我正在使用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();

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


问题答案:

在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的答案。



 类似资料:
  • 问题内容: 我想捕获并显示通过Python的子流程调用的流程的输出。 我以为我可以将文件状对象作为参数stdout和stderr传递 我可以看到它访问了属性-因此它正在处理对象。但是,永远不会调用该方法。我的方法是否完全无效或我只是缺少什么? 更新: 我还想工作的是ANSI控制字符,用于移动光标并覆盖以前的输出内容。我不知道这是否是正确的术语,但这是我的意思的一个示例:我正在尝试使一些GIT自动化

  • 问题内容: 在shell中,您可以执行重定向 等操作,但是启动程序后如何呢? 这就是我问这个问题的方式,在我的终端后台运行的程序不断输出令人讨厌的文本。这是一个重要的过程,因此我必须打开另一个shell以避免输入文本。我希望能够进行重定向或其他重定向,以便可以继续在同一外壳中工作。 问题答案: 除非关闭并重新打开您的tty(即注销并重新登录,这可能还会终止该过程中的某些后台进程),否则您只剩下一个

  • 问题内容: 如果我通过Java的ProcessBuilder类启动流程,则可以完全访问该流程的标准输入,标准输出和标准错误流(如Java 和)。不过,我不能找到一种方法,这些流无缝连接,和。 可以用来获取包含子流程的标准输出和标准错误的单个文件,然后循环遍历并通过我的标准输出将其发送出去,但是我找不到一种方法可以让用户输入到流程中,如果我使用C 调用,他或她可以。 Java SE 7发行时似乎有可

  • 我完全混淆了,,。 哪个是阻塞,哪个不是? 我的意思是如果我使用父进程是否等待子进程返回/才继续执行。 如何影响这些调用?

  • 线程实例的join()方法可用于将一个线程的执行开始“连接”到另一个线程的执行结束,这样一个线程在另一个线程结束之前不会开始运行。如果对线程实例调用join(),则当前运行的线程将阻塞,直到线程实例完成执行 但是如果我有多个线程并且当我在循环内部调用join时。所有线程并行运行。但是根据连接的概念,首先连接的线程应该完成,然后只有主线程才允许连接其他线程。 } 在上面的代码中,如果第一个线程被连接

  • 我正在尝试用Python编写一个程序。我想写的是一个脚本,它会立即向用户返回一条友好的消息,但会在后台生成一个长的子进程,它会处理几个不同的文件,并将它们写入一个祖父文件。我已经做了一些关于线程和处理的教程,但我遇到的是,无论我尝试什么,程序都会一直等待,直到子进程完成,然后才会向用户显示前面提到的友好消息。以下是我尝试过的: 线程示例: 我读过这些关于多线程的SO帖子如何在Python中使用线程