Revised: Mar./10th/2002
多くの言語でパイプと言う仕組みが提供されています。それらは一般に、あるプロセスの出力を別のプロセスの入力に繋げることです。
例えば UNIX 系 OS では、コマンド "cat /etc/passwd | wc -l
" とすることで、 "cat /etc/passwd
" の出力を "wc -l
" の入力に与えることが出来ます。 Java では、文字ストリームのパイプとバイトストリームのパイプが用意されています。
文字ストリーム |
PipedReader PipedWriter
|
---|---|
バイトストリーム |
PipedInputStream PipedOutputStream
|
例えば、メソッドの中で次のようにパイプの入り口と出口を作ります:
PipedWriter pipeOut = new PipedWriter(); PipedReader pipeIn = new PipedReader(pipeOut);
この例では、 pipeOut
から取得したストリームはそのまま pipeIn
から取得できます。つまり、書き込みの文字ストリームを読み込みの文字ストリームにつなげたことになります。
pipeOut
をこのメソッド内で処理して戻り値に pipeIn
を指定すれば、このメソッドの処理結果を書き込むストリームを、読み込みのストリームにパイプを通して繋げられるわけです。
例えば、これに続いて次のように書いたとします:
// ファイルのインスタンス化 FileReader source = new FileReader("words.txt"); // 読み込みバッファでラップ BufferedReader in = new BufferedReader(source); // 書き込みのパイプを PrintWriter でラップ PrintWriter out = new PrintWriter(pipeOut); // 読み込みバッファから読み込んで書き込み String line; while ((line = in.readLine()) != null) { out.println(line); out.flush(); } out.close();
このプロセスで out
に書き込まれたモノはパイプストリーム PipeOut
に渡され、パイプを通って pipeIn
から読み込むことが出来ます。従って、このメソッドで return pipeIn;
とすれば、次の制御へパイプがつながるわけです。
このプロセスを実行するメソッドを Reader pipe(Reader source)
として定義すれば、引数 source
で受け取ったストリームを pipeOut
に書き込んで、それを pipeOut
に出力して返すことが可能です。
次のサンプルは、テキストファイルに行番号を付加して、行を逆に並べて、更に行番号を付加するものです。この三つのプロセス間ではストリームがパイプでつながれています。
PipeTest.java
:
import java.io.*; import java.util.*; class PipeTest { public static void main(String[] args) throws IOException { // ファイルのインスタンス化 FileReader text = new FileReader(args[0]); // パイプを利用した複数の処理 Reader nlText = nl(tac(nl(text))); // 標準出力 BufferedReader in = new BufferedReader(nlText); String line; while ((line = in.readLine()) != null) { System.out.println(line); } in.close(); } // パイプを利用した処理:行番号付加 static Reader nl(Reader source) throws IOException { BufferedReader in = new BufferedReader(source); // 読み込みと書き込みのパイプをつなげる PipedWriter pipeOut = new PipedWriter(); PipedReader pipeIn = new PipedReader(pipeOut); PrintWriter out = new PrintWriter(pipeOut); // out に処理 String line; int i=0; while ((line = in.readLine()) != null) { out.println(++i + ": " + line); out.flush(); } out.close(); // 読み込みパイプを返す return pipeIn; } // パイプを利用した処理:逆順に並べ替え static Reader tac(Reader source) throws IOException { BufferedReader in = new BufferedReader(source); // 読み込みと書き込みのパイプをつなげる PipedWriter pipeOut = new PipedWriter(); PipedReader pipeIn = new PipedReader(pipeOut); PrintWriter out = new PrintWriter(pipeOut); // out に処理 Stack rtext = new Stack(); String line; int i=0; while ((line = in.readLine()) != null) { rtext.push(line); } while (!rtext.empty()) { out.println(rtext.pop()); out.flush(); } out.close(); // 読み込みパイプを返す return pipeIn; } }
次の例は、同じディレクトリにテキストファイル test.txt
が存在した場合の実行例です。テキストファイルはOS標準のエンコードで用意します。 Windows では Shift_JIS です。
test.txt
:
こんにちは Hello World. さようなら Bye World.
コマンドライン:
C:\IO>javac PipeTest.java C:\IO>java PipeTest test.txt 1: 5: Bye World. 2: 4: さようなら 3: 3: 4: 2: Hello World. 5: 1: こんにちは C:\IO>