2011-04-25 30 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的方式来连接字符串。