2011-04-25 69 views
1

我試圖在兩個Java程序之間管道文本。爲了簡便起見,我提出這樣的代碼:命令外殼上的java進程之間的管道不可靠的工作

import java.io.DataInputStream; 
import java.io.IOException; 

public class Test { 
    public static void main(String[] args) throws IOException { 
     DataInputStream stdin = new DataInputStream(System.in); 
     String completeText = ""; 

     while (stdin.available() > 0) { 
      byte[] tempByte = { stdin.readByte() }; 
      completeText += new String(tempByte); 
     } 

     System.out.println(completeText); 
    } 
} 

當執行在Linux或Windows下,文本似乎得到省略,因爲如果管道被封堵或失去了相當隨機的。有時候一切都會通過,有時不會:

echo "omg wtf" | java Test | java Test 

對此的任何想法?看起來,文本越容易經歷cpu越慢。當輸入從java System.out.println()管道輸出時,是否「可用」返回錯誤的結果?

乾杯!

回答

4

首先,available()方法不是確定流是否耗盡的可靠方法。流結束的可靠指示是通過檢查read()方法的返回值(< 0意味着流結束)。

簡而言之,如果流暫時爲空,available()可以返回false(這將終止循環)。如果管道仍處於活動狀態,則管道另一端的進程在其中寫入一些字節後,此情況將會立即發生變化。爲了確保所有數據都被讀取,您需要檢查流結束。其次,如果你想讀取字符(並將它們連接成一個字符串),你應該從Reader(而不是從一個流中的字節)讀取字符。這將允許您的代碼處理unicode字符。

第三,如果使用StringBuilder(而不是普通字符串),大塊字符的連接將會更快。最後,如果您只需要讀取字節,則可以直接使用輸入流(無需使用DataInputStream包裝它)。

以下是我會寫:

Reader r = new InputStreamReader(System.in); 
StringBuilder sb = new StringBuilder(); 
while(true) { 
    int ch = r.read(); 
    if(ch < 0) 
    break; 
    sb.append((char) ch); 
} 

System.out.println(sb.toString()); 
3

available()是不可靠的管道輸入。它檢查當前進程的輸入緩衝區中是否有數據。它無法檢查前面(管道式)過程是否要發送一些數據。

在你的情況下,阻塞讀的是一個可接受的方案:

public class Test { 
    public static void main(String[] args) throws IOException { 
     DataInputStream stdin = new DataInputStream(System.in); 
     StringBuilder completeText = new StringBuilder(); 
     byte[] tempByte = new byte[1024]; 
     int len = 0; 
     while ((len = stdin.read(tempByte)) != -1) { 
      completeText.append(new String(tempByte, 0, len)); 
     } 
     System.out.println(completeText.toString()); 
    } 
} 

我還添加了StringBuilder的,因爲這是「正確的」 Java的方式來連接字符串。