Revised: Mar./10th/2002
多くの言語でパイプと言う仕組みが提供されています。それらは一般に、あるプロセスの出力を別のプロセスの入力に繋げることです。
例えば UNIX 系 OS では、コマンド "cat /etc/passwd | wc -l" とすることで、 "cat /etc/passwd" の出力を "wc -l" の入力に与えることが出来ます。 Java では、文字ストリームのパイプとバイトストリームのパイプが用意されています。
| 文字ストリーム |
PipedReaderPipedWriter
|
|---|---|
| バイトストリーム |
PipedInputStreamPipedOutputStream
|
例えば、メソッドの中で次のようにパイプの入り口と出口を作ります:
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>