今回はパイプストリームについて紹介したいと思います。

 

●使い道

 

他のブログやAPIリファレンスに書いてある通り、プログラムの出力結果をパイプします。

Linuxコマンドのパイプのように、あるプログラムの出力結果を別のプログラムの入力としたいときに使用します。

実際にJavaプログラム間でデータのやり取りをするとき、データオブジェクトを介して行います。データオブジェクトにデータを格納したほうがデバッグでデータを簡単に参照できて利便性がよいため、パイプを使う場面はあまりありません。

 

それをあえてパイプを使うのは、何らかの制約があるためです。

例えば、PrintWriterで結果を出力するAPIを使うときです。

例.ECJ(Eclipse Compiler for Java)のコンパイルメソッド
  コンパイル結果をPrintWriterで出力する。

 

このようなときは、APIを修正するわけにもいかないため(APIをメンテナンスするのなら修正してもよいと思いますが)、PrintWriterからパイプして、後続プログラムに結果を渡します。

 

●設計の注意点                                               

 

★バッファサイズ

一度読み込んだデータはパイプ内に保管されます。

パイプ内で保管できる容量は限度があり、コンストラクタで指定できます。

(ただし、Java5ではバッファサイズは1024byteで変更不可)

APIリファレンスに書いていませんが、バッファサイズに到達するとデータを読み出すまで、無限ループをします。

バッファサイズはメッセージのサイズによって決めるのが望ましいです。

ただ、メッセージのサイズが決まっていない場合はバッファサイズを超えることがあります。

その場合は非同期でデータを読み出す必要があります。前段のプログラムが終わるまでデータオブジェクトに逐次格納するか、後続のプログラムを非同期で実行してしまうなどの策が考えられます。

 

 

●サンプル                                                  

例.ECJ(Eclipse Compiler for Java)のコンパイル結果(ワーニング、エラー)をパイプする

※見やすくするため、コードを一部省略しています。

 PipedWriter pw = new PipedWriter();
 PipedReader pr = new PipedReader(pw);
 // PrintWriterにPipedWriterをセット
 PrintWriter print = new PrintWriter(pw);
 // APIにPrintWriterを渡す
 BatchCompiler.compile(
  new String[]{"none"},
  print,
  print,
  null
 );
 pw.close();

 

 StringBuffer msg = new StringBuffer();
 if (pr.ready()) {
  char[] cbuf = new char[1024];
 // 出力メッセージをパイプから取り出して、msgに格納する
  pr.read(cbuf, 0, 1024);
  msg.append(new String(cbuf).trim());
 }

 

●参考


http://www1.megaegg.ne.jp/~yasu/Programmer's%20Page/stream/PipedStream.html