2010-11-20 71 views
2

我正在爲Java中的命令行程序編寫終端包裝,並使用ProcessBuilder產生子進程。要將擊鍵發送到子進程,我只需從GUI直接寫入e.getKeyChar()到由proc.getOutputStream()給出的OutputStream即可。爲了接收從子進程的輸出,我基本上有一個while循環,從讀取子的stdoutJava:無法從進程獲取標準輸出數據,除非手動刷新

while ((b = br.read()) != -1) { 
    System.out.println("Read "+b); 
    bb[0] = (byte) b; 
    // call an event listener with the read byte 
    listener.dataReceived(bb); 
} 

這工作,只有,如果我馬上刷新上兩個兩端輸出。也就是說,我必須刷新每個用戶輸入,並且子進程必須刷新它自己的stdout才能發生。否則,read()塊,等待數據,這是永遠不會實際發送(子進程'stdout只是保持緩衝)。我如何獲得I/O?

例終端子:

#include <stdio.h> 

int main() { 
    char c; 
    while((c = getchar()) != -1) { 
     printf("Got: %d\n", c); 
     // doesn't work in my Java program if the next line isn't present 
     fflush(stdout); 
    } 
    return 0; 
} 

我在Ubuntu 10.10上運行使用Sun Java 6

回答

1

很多很多運行時庫(例如,我知道libc這樣做,如果其他人也不會感到驚訝)會默認緩衝其輸出,除了輸出到終端時的。這在處理多條線路(例如,在正常管道中)時極大地提高了數據處理的效率,但是當只有少量信息時,這會傷害很多。如果您有權訪問子進程的源代碼,則最好通過關閉緩衝或添加刷新來更新代碼。

但這並非總是可行,特別是在處理第三方代碼時。最好的其他修復我知道在這種情況下是使用像Expect這樣的工具來欺騙子進程。在內部,Expect知道如何假裝成爲一個終端(在Unix上使用ptys和在Windows上godawful黑客),以欺騙其他程序關閉(或至少減少)緩衝。對於Expect,有一個腳本 - 非緩衝區 - 使其專注於此類用途。 (通常它可以做的不僅僅是處理不規則的緩衝,但它是最好的解決辦法。)

4

,直到數據已被寫入到磁盤你不能從文件中讀取數據。 直到數據被放入管道/套接字緩衝區後,才能從套接字或管道讀取數據。

當外部進程刷新其輸出並將數據寫入磁盤/管道緩衝區/套接字緩衝區時,您的java程序無法控制(*)。你完全處於外部程序的緩衝行爲的擺佈之中。每個操作系統和每種編程語言都是如此。

每個網絡程序員都必須處理這個問題,所以只需處理它。 (*) - 有時某些程序(如cat)有選項(-u)指示程序使用無緩衝輸出。否則你是仁慈的

+0

對,但是用我的Java程序,I/O *永遠不會*發送,而如果我手動在終端中運行所述子進程,I/O幾乎是即時的。 – erjiang 2010-11-20 17:22:33

+0

是的,我們知道我們必須處理它。問題是如何。 – jononomo 2013-08-19 17:56:24

0

你沒有從事件調度線程運行你的I/O讀取循環嗎?

您應該在單獨的線程中運行從子進程讀取的I/O(如果您還沒有這樣做)。立即刷新到每個GUI按鍵的子過程可能是最好的;除非你想支持某種'一次讀完整行'的東西。

+0

這就是我目前正在做的。我有一個單獨的線程從子進程讀取(因爲'read()'塊),它通知主線程中的事件處理程序。鍵擊會立即發送到子流程並刷新。 – erjiang 2010-11-21 00:44:50

相關問題