2012-05-11 32 views
1

Java中的交互過程存在問題。我有線程來讀取STDOUT和STDERR以及一個線程來處理進程的輸入。但是,在進程終止之前,STDOUT流中沒有可用的數據。然後是整個輸出打印一次。Java exec - 交互過程的輸出一直保持到過程終止

DBG | Pipe action-STDERR started 
DBG | Pipe action-STDIN started 
DBG | Pipe action-STDOUT started 

STDIN | Try to put some input. 
STDIN | I cannot see any output. 
STDIN | Nevertheless the interaction works. 
STDIN | It works on background. 
STDIN | Let's terminate the process to see the truth. 
STDIN | quit 

STDOUT | Enter some text, please: The text is 'Try to put some input.' 
STDOUT | Enter some text, please: The text is 'I cannot see any output.' 
STDOUT | Enter some text, please: The text is 'Nevertheless the' 
STDOUT | Enter some text, please: The text is 'interaction works.' 
STDOUT | Enter some text, please: The text is 'It works on background.' 
STDOUT | Enter some text, please: The text is 'Let's terminate the process to see the truth.' 
STDOUT | Enter some text, please: The text is 'quit' 
STDOUT | Bye! 
DBG | Trying to kill thread action-STDOUT 
DBG | Trying to kill thread action-STDERR 
DBG | Trying to kill thread action-STDIN 
DBG | Pipe action-STDERR finished 
DBG | Finished 
DBG | Pipe action-STDIN finished 
DBG | Pipe action-STDOUT finished 

以STDOUT作爲前綴的行是由進程寫入的行。以STDIN作爲前綴的行是我寫的行。以DBG爲前綴的行是被測試的Java程序寫入的行作爲調試信息。讓我們嘗試在系統控制檯中執行相同的過程。

這種行爲完全符合我的期望。我被要求輸入一些信息。我這樣做,並得到答案。

我很驚訝,我發現在網上的幾個帖子包括Stackoverflow,但沒有任何答案標記爲可接受的解決方案。 (例如Problem reading InputStream from Java Process。)似乎Java開發人員從未處理交互式進程的執行。奇怪的是,當進程正在運行時,非交互式進程(如ping)的輸出順序出現。沒有任何問題。但是當進程等待用戶輸入時,輸出會以某種方式被阻止。

+0

寫入的其他進程(「服務器」)是什麼,並且它確保每次都刷新其stdout? –

+0

可能不是,但是這個過程在這個級別是黑盒子。不管它是否沖洗它的輸出都不重要,因爲我不能影響它。我必須解決Java代碼中的問題。 –

回答

1

遺憾的是它不是一個bug,它是一個功能。無論是在Linux上還是在Windows上,管道都是這樣實現的。它們被緩衝以提高性能。一個過程產生數據,第二個過程產生數據。沒有交互需要,這種模式也適用於99%的情況。

但是,控制檯是另一種應用程序。系統控制檯是操作系統的一部分,它與我們用Java編寫的控制檯有點不同。系統控制檯當然會立即打印所有數據。一切正常。然後從我們的代碼執行相同的過程不會打印提示,儘管它可以工作。怎麼了?系統控制檯和進程之間沒有緩衝區。但是在我們的流程和我們的Java代碼之間有相反的緩衝區。這就是原因。

該過程不會自動刷新輸出。無論寫入進程的語言如何。用Java,Perl或C編寫的進程都不會打印提示,直到將明確刷新添加到其代碼中爲止。如果你能影響一個過程中,你將與互動,更新的代碼(僞如下)的代碼:

print 'Give me a number ' 
flush STDOUT 
number = get STDIN 
print 'You wrote ' + number 
flush STDOUT 

沒有另一種解決方案。如果第三方應用程序未刷新其輸出,則無法在控制檯中使用它。你幾乎無法避免緩衝。儘管如此,還是有可能的。有庫或者你可以找到一個開源的應用程序,它可以與有問題的進程進行交互並檢查其代碼。

小費:退房Apache Commons Exec。這是一個專門從事流程執行的圖書館。