2009-11-13 115 views
16

我想从Groovy程序中执行foo.bat,并将生成的过程输出重定向到标准输出。 Java或Groovy代码示例都可以。将过程输出重定向到标准输出

foo.bat可能需要几分钟的时间才能运行并生成大量的输出,所以我希望在生成它时立即看到输出,而不必等到处理完成才能看到所有输出立刻。

+0

类似http://stackoverflow.com/questions/1670798/using-a-thread-to-capture-process-output – yegor256 2013-01-02 15:44:25

回答

29

它使用一个读取所有输出执行的程序生成的类,并将其显示在它自己的stdout中。

class StreamGobbler extends Thread { 
    InputStream is; 

    // reads everything from is until empty. 
    StreamGobbler(InputStream is) { 
     this.is = is; 
    } 

    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(line);  
     } catch (IOException ioe) { 
      ioe.printStackTrace(); 
     } 
    } 
} 

Runtime rt = Runtime.getRuntime(); 
Process proc = rt.exec("javac"); 
//output both stdout and stderr data from proc to stdout of this process 
StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream()); 
StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream()); 
errorGobbler.start(); 
outputGobbler.start(); 
proc.waitFor(); 
+1

我的问题是,如果过程没有在此刻输出什么东东,循环将在过程结束之前结束,对吧? – 2015-09-03 10:41:19

+0

while循环将一直等到下一行输入。 – Crummy 2016-07-28 13:49:31

4

如果你只是想抓住一个简单命令的输出,这里有点简单。如果要并行处理或者命令使用stdin或生成stderr,则需要使用像jitter一样的线程。

如果您获得大量输出,请使用缓冲副本(如this)。

import java.io.*; 
public class test { 
    static void copy(InputStream in, OutputStream out) throws IOException { 
    while (true) { 
     int c = in.read(); 
     if (c == -1) break; 
     out.write((char)c); 
    } 
    } 

    public static void main(String[] args) throws IOException, InterruptedException { 
    String cmd = "echo foo"; 
    Process p = Runtime.getRuntime().exec(cmd); 
    copy(p.getInputStream(), System.out); 
    p.waitFor(); 
    } 
} 
4

下面Groovy代码将执行foo.bat和输出发送到标准输出:

println "foo.bat".execute().text 
+4

我认为这将只在打印完成后打印所有输出。我想在生成后立即看到输出 – 2009-11-16 15:15:57

+1

另外,如果foo.bat的输出对于标准输出缓冲区“太大”,这将停止执行foo.bat。 – billjamesdev 2013-11-08 02:11:21

2

异步的方式来实现它。

void inputStreamToOutputStream(final InputStream inputStream, final OutputStream out) { 
    Thread t = new Thread(new Runnable() { 

     public void run() { 
      try { 
       int d; 
       while ((d = inputStream.read()) != -1) { 
        out.write(d); 
       } 
      } catch (IOException ex) { 
       //TODO make a callback on exception. 
      } 
     } 
    }); 
    t.setDaemon(true); 
    t.start(); 
} 

{ 
    Process p = ...; 
    inputStreamToOutputStream(p.getErrorStream(), System.out); 
    inputStreamToOutputStream(p.getInputStream(), System.out); 
} 
6

如果你正在寻找更多的Groovy和更少的Java做到这一点,这将打印各行,因为它发生:

def cmd = "./longRunningProcess" 

def process = cmd.execute() 
process.in.eachLine { line -> println line } 

另外,如果你想看到stdout和stderr

def cmd = "./longRunningProcess" 

def process = cmd.execute() 
process.waitForProcessOutput(System.out, System.err) 
35

使用inheritIO()方法将所有流重定向到标准输出很简单。这会将输出打印到正在运行此命令的进程的stdout。

ProcessBuilder pb = new ProcessBuilder("command", "argument"); 
pb.directory(new File(<directory from where you want to run the command>)); 
pb.inheritIO(); 
Process p = pb.start(); 
p.waitFor(); 

也存在其他方法,如下所述。这些单独的方法将帮助仅重定向所需的流。

pb.redirectInput(Redirect.INHERIT) 
    pb.redirectOutput(Redirect.INHERIT) 
    pb.redirectError(Redirect.INHERIT) 
+1

这是正确回答问题的答案。 OP询问如何重定向输出,而不是如何打印输出的每一行。非常重要的区别 – Brandon 2016-12-10 01:19:19

+1

我不能满足这一点,你已经帮了我很多。 – 2017-11-23 11:31:06