猿问

ProcessBuilder:转发stdout和stderr启动进程而不阻塞主线程

ProcessBuilder:转发stdout和stderr启动进程而不阻塞主线程

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

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


一只萌萌小番薯
浏览 1235回答 3
3回答

慕的地6264312

使用ProcessBuilder.inheritIO它,它将子进程标准I / O的源和目标设置为与当前Java进程的源和目标相同。Process p = new ProcessBuilder().inheritIO().command("command1").start();如果Java 7不是一个选项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();}子进程完成后线程将自动死亡,因为srcEOF 会自动死亡。

HUX布斯

一个灵活的Java 8 lambda解决方案,允许您提供一个Consumer逐行处理输出(例如,记录它)的解决方案。run()是一个没有检查异常抛出的单线程。作为实施的替代Runnable,它可以Thread像其他答案所暗示的那样延伸。class&nbsp;StreamGobbler&nbsp;implements&nbsp;Runnable&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;InputStream&nbsp;inputStream; &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Consumer<String>&nbsp;consumeInputLine; &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;StreamGobbler(InputStream&nbsp;inputStream,&nbsp;Consumer<String>&nbsp;consumeInputLine)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.inputStream&nbsp;=&nbsp;inputStream; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.consumeInputLine&nbsp;=&nbsp;consumeInputLine; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;BufferedReader(new&nbsp;InputStreamReader(inputStream)).lines().forEach(consumeInputLine); &nbsp;&nbsp;&nbsp;&nbsp;}}然后你可以使用它,例如:public&nbsp;void&nbsp;runProcessWithGobblers()&nbsp;throws&nbsp;IOException,&nbsp;InterruptedException&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;Process&nbsp;p&nbsp;=&nbsp;new&nbsp;ProcessBuilder("...").start(); &nbsp;&nbsp;&nbsp;&nbsp;Logger&nbsp;logger&nbsp;=&nbsp;LoggerFactory.getLogger(getClass()); &nbsp;&nbsp;&nbsp;&nbsp;StreamGobbler&nbsp;outputGobbler&nbsp;=&nbsp;new&nbsp;StreamGobbler(p.getInputStream(),&nbsp;System.out::println); &nbsp;&nbsp;&nbsp;&nbsp;StreamGobbler&nbsp;errorGobbler&nbsp;=&nbsp;new&nbsp;StreamGobbler(p.getErrorStream(),&nbsp;logger::error); &nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;Thread(outputGobbler).start(); &nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;Thread(errorGobbler).start(); &nbsp;&nbsp;&nbsp;&nbsp;p.waitFor();}这里输出流被重定向到,System.out并且错误级别由错误级别记录logger。
随时随地看视频慕课网APP

相关分类

Java
我要回答