2014-01-16 59 views
0

我試圖在日誌文件上寫出通過Runtime.getRuntime()。exec()啓動的輸出或Java程序。我使用下面的代碼。使用Runtime.getRuntime()啓動的Java程序的輸出exec()

public class Thread_Write extends Thread { 
    int id; 

    public void run() { 
     try { 
      File log = new File("./log"+id+".txt"); 
      log.createNewFile(); 
      FileWriter fw = new FileWriter("./"+"log"+id+".txt",true); 
      Runtime runtime = Runtime.getRuntime(); 
      Process process = runtime.exec("java WriteToFile "+id); 
      InputStream is = process.getInputStream(); 
      InputStreamReader isr = new InputStreamReader(is); 
      BufferedReader br = new BufferedReader(isr); 
      String line; 
      while ((line = br.readLine()) != null) { 
       fw.write(line); 
       } 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public Thread_Write(int i) { 
     super(); 
     this.id = i; 
    } 

    public static void main(String[] args) { 
     for (int i =0 ; i<10;i++) { 
      (new Thread_Write(i)).start(); 
     } 
    } 
} 

「java WriteToFile id」假設在終端上寫入異常,但不幸的是,我沒有收到任何東西。奇怪的是,如果我改變這個命令,「回聲測試」,「測試」將被正確添加到日誌文件的末尾。任何想法爲什麼?

乾杯。

+4

可能是因爲它寫入了進程的錯誤流,而不是它的輸入流。 – assylias

回答

2

最有可能的原因是異常進入錯誤流。一種選擇是重定向錯誤流:process.getErrorStream()

或者您可以使用a ProcessBuilder

ProcessBuilder pb = new ProcessBuilder("java", "WriteToFile", String.valueOf(id)); 
pb.redirectErrorStream(true); 
pb.redirectOutput(log); 
Process p = pb.start(); 
+1

不僅如此,我們可以完全放棄使用InputStream,而是使用'redirectOutput(log)'來代替。 – VGR

+0

確實非常好。 – assylias

1

錯誤不可通過process.getInputStream(),您需要改爲使用process.getErrorStream()。另一種方法是首先使用processBuilder.redirectErrorStream(true)。這將導致stdout和stderr在process.getInputStream()上可用。

0

有幾個問題在這裏。這是我會怎麼寫的run()方法(原理如下圖):

public void run() { 
    try { 
    Process process = Runtime.getRuntime().exec("java WriteToFile " + id); 
    Thread err = consume(process.getErrorStream(), 
     new FileOutputStream("./" + "log" + id + ".txt")); 
    Thread std = consume(process.getInputStream(), 
     new FileOutputStream("./" + "log_stdout" + id + ".txt")); 

    err.join(); 
    std.join(); 

    } catch (Exception e) { 
    e.printStackTrace(); 
    } 
} 

private Thread consume(final InputStream stream, 
    final OutputStream out) { 
    Thread result = new Thread() { 
    public void run() { 
     PrintWriter pw = new PrintWriter(out, true); 
     try (Scanner sc = new Scanner(stream)) { 
     while (sc.hasNext()) { 
      pw.println(sc.nextLine()); 
     } 
     } 
    } 
    }; 
    result.start(); 
    return result; 
} 

(1)最重要的是:如果WriteToFile寫入到兩個標準錯誤和標準輸出,你的進程將阻止:因爲它只能從標準錯誤讀取,有沒有人讀取stdout緩衝區的字節。一旦這個緩衝區填滿了,WriteToFile會阻塞在下一個println()上。假設在發生異常之前發生這種情況,兩個進程都會死鎖,每個進程都在等待另一個進程的第一步。解決方案:產生兩個線程,一個用於消耗stdout,另一個用於消耗stderr。

其他(未成年人)的問題: (2)而不是包裹在InputStreamReaderInputStream,反過來,上纏繞有BufferedReader裏面,你可以使用掃描儀類:它的構造可以採取InputStream和它給你的readLine ()方法,你需要。 (3)如果僅在log.createNewFile();中使用唯一用途,則不需要創建log變量 - 輸出文件將由您的FileWriter對象爲您創建。

(4)您可能會想要使用PrintWriter對象而不是FileWriter。前者爲您提供println(),它允許您逐行打印輸出。

相關問題