2012-10-31 40 views
0

我希望能夠從Java產生一個外部進程,並定期寫入其輸入並讀取響應,就好像它是控制檯一樣。然而,大多數時候,當我讀取過程的輸出時,沒有任何東西可用。有沒有一種很好的做法來做這種事情(甚至避免它)?如何可靠地讀寫從Java運行的外部進程?

這裏有什麼行不通一個精簡例如:

import org.apache.commons.exec.*; 
import java.io.*; 
//... 
CommandLine cl = CommandLine.parse("/usr/bin/awk {print($1-1)}"); 
System.out.println(cl.toStrings()); 
Process proc = new ProcessBuilder(cl.toStrings()).start(); 
OutputStream os = proc.getOutputStream(); // avoiding *Buffered* classes 
InputStream is = proc.getInputStream(); // to lessen buffering complications 
os.write(("4" + System.getProperty("line.separator")).getBytes()); 
os.flush(); // Doesn't seem to flush. 
// os.close(); // uncommenting works, but I'd like to keep the process running 
System.out.println("reading"); 
System.out.println(is.read()); // read even one byte? usually is.available() -> 0 

奇怪的是,如果我包裹起來的OutputStream中的BufferedWriter中,我可以從一些過程(貓)閱讀,而不是其他( awk,grep)。

+0

查看我的答案,如果它有幫助,http://stackoverflow.com/questions/13008526/runtime-getruntime-execcmd-hanging/13008847#13008847 – Arham

+0

謝謝,阿罕姆。我沒有考慮過stdErr可能會填滿並消除同步問題是一個不錯的方法。儘管如此,在單獨的線程中從stdErr中讀取這些信息並沒有幫助。我希望能夠將數據推送到流程,讓流程工作 - 例如處理流水線或等待任何響應,然後繼續前進,如從shell運行。我應該用bash -c「...」來包裝我的外部過程嗎? – jlb

+0

我還沒有嘗試過運行unix進程,但在java中的Windows進程,你必須嘗試一下。但據我所知,您希望自己控制應用程序的退出,而不是系統。爲此,你總是可以把proc.destroy()放入一個自定義的條件中。 – Arham

回答

1

通常,採取的方法是正確的。儘管如此:

  1. InputStream.read()是一種阻塞方法。它等待輸入並且不是CPU密集型的。你應該圍繞它...
  2. 多於一個字節可以讀,只是用read(byte[] buffer, int offset, int len)
  3. 包裝輸入流來的BufferedInputStream簡化了訪問(readLine()方法)。這是BufferedReader的替代方法。
  4. 不要忘記使用Process.waitFor()

此外,請確保外部進程寫入標準輸出(而不是標準錯誤)。兩種可能性在這裏:

  1. 使用Process.getErrorStream()(並把它當作另一種爲InputStream)
  2. 改變命令行/usr/bin/awk {print($1-1)} 2>&1。這會將標準錯誤重定向到標準輸出。
+0

謝謝,user999441。 Process.waitFor()阻塞,直到完成外部進程。我想保持進程運行並在其終止之前從其輸出中讀取。 – jlb

+0

直到你殺死它,或者通過字面上的殺戮,或者通過發送EOF(Ctrl + D),該進程纔會結束。或Ctrl + C。另外,運行一個文件作爲輸入和輸出的進程可能是一個更好的主意 - 進程在文件中輸入,執行作業,將文件寫入文件,完成,然後由Java處理輸出文件。 –

相關問題