2009-11-13 116 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