2014-01-08 51 views
3

雖然建立一個包裝爲我遇到這個奇怪的問題,即連接到外部過程的輸出(stdout)的輸入流是完全空白直到外部傳來的控制檯應用程序進程退出。從的ProcessBuilder的InputStream中,直到外部進程沒有輸入關閉

我的如下代碼:

import java.io.BufferedReader; 
import java.io.File; 
import java.io.IOException; 

public class Example{ 

    public static void main(String args[]) throws IOException{ 
     File executable = ... 

     ProcessBuilder pb = new ProcessBuilder(executable.getCanonicalPath()); 

     pb.redirectErrorStream(true); 

     Process p = pb.start(); 

     BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8"))); 

     String line; 

     while((line = br.readLine()) != null){ 
      System.out.println(line); 
     } 
    } 
} 

我試圖從輸入流和所有的閱讀幾個變種導致相同的行爲。

我已經試過:

CharBuffer charBuf = CharBuffer.allocate(1000); 

InputStreamReader isr = new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8")); 

while(isr.read(charBuf) != -1){ 
    System.out.print(charBuf.flip().toString()); 
} 

byte[] buf = new byte[1000]; 
int r; 

while((r = p.getInputStream().read(buf)) != -1){ 
    System.out.print(new String(buf, 0, r)); 
} 

都無濟於事。

某處沿線外部過程的輸出被無限期地緩衝,我無法弄清楚在哪裏。從命令行加載進程似乎正常工作,我看到輸出瞬間出現。最奇怪的部分是外部進程終止導致所有「緩衝」輸出同時氾濫的事實(很多東西)。

不幸的是,我不能訪問外部進程的源代碼,但考慮到它在寫入到stdout時很好,因爲在控制檯中應該不會真的有所作爲(據我所知)。

歡迎任何想法。

編輯:

一個答案推薦我重寫了輸出和錯誤流在一個單獨的線程中運行的讀者。 我的實際執行情況是這樣做的!但問題仍然存在。上面貼出的代碼是爲實現可讀性而精簡的實際代碼的SSCCE,實際代碼涉及用於從InputStream中讀取的單獨線程。

編輯2:

用戶FoggyDay似乎提供如何控制檯和非控制檯之間輸出時輸出緩衝變化的行爲,其限定了答案。雖然檢測到他們正在寫入控制檯的進程使用行緩衝(緩衝刷新每一行),但寫入非控制檯(檢測到的不是控制檯的所有內容)可能會被完全緩衝(大小爲8K )。如果我將外部過程垃圾郵件(for循環中的8%of lorem ipsum)輸出確實出現。我想現在我的問題是如何使我的java程序觸發線緩衝在外部進程。

+1

如果你不想緩衝,爲什麼要使用'BufferedReader'?我可能會轉而使用java.util.Scanner。 –

+0

@ElliottFrisch最初我想要某種形式的緩衝,但是由於沒有完全解決,我開始使用'CharBuffer'並嘗試排查問題。我的最後一次嘗試是直接讀取原始InputStream並仍然沒有輸出。鑑於Scanner建立在原始InputStream的基礎之上,我沒有看到它是如何工作的,但無論如何我都會試一試。 – initramfs

+0

我假設你已經用其他可執行文件試過了你的代碼,並且在過程結束之前看到它的輸出是可用的嗎?任何可能性這個可執行文件都在做一些奇怪的事情,比如檢查輸出是否被重定向? –

回答

-1

某些軟件檢查它是否正在寫入終端並將行爲切換到無緩衝輸出。這可能是一個原因,爲什麼它在終端中工作。將輸出管道傳輸給cat並查看輸出是否仍然立即顯示。

另一個原因可能是程序在執行某些操作之前正在等待輸入或關閉其stdin,儘管這與目前所描述的症狀並不相符。

1

你的問題 「如何讓我的java程序觸發線緩衝的外部進程」:

在Linux上,你可以使用 「stdbuf」 程序(coreutils軟件包):stdbuf -oL your_program program_args

您只需要更改stdout,因爲stderr在默認情況下是無緩衝的。如果你感興趣,setlinebuf的手冊頁給出了額外的背景信息:http://linux.die.net/man/3/setlinebuf

+0

我的應用程序是爲了跨平臺的,所以一個linux專用的解決方案不夠好。我會看看stdbuf的來源,但看看我能做些什麼。 – initramfs

+0

在windows中試過這個(git自帶stdbuf.exe),它似乎不起作用,我猜JDK是buffereing? – teknopaul