Previous | Next | Trail Map | Writing Java Programs | 入出力ストリーム


ストリームを使用したパイプの実装

java.io パッケージは、 PipedInputStreams(in the API reference documentation)PipedOutputStream(in the API reference documentation)の2つのクラスを含んでおり、パイプの入出力コンポーネントを実装する。 パイプは、プログラム(あるいはスレッド)からの出力を別のプログラムの入力に接続するために使用される。

パイプ処理された入出力ストリームは、他者によって入力として用いらる出力を生成するメソッドに便利である。 たとえば、テキストをソートしたり、逆転するなどの種々のテキストユーティリティを実装するクラスを書いていると仮定する。 (注:「逆転する」とは単語中の文字を逆順に並び替えること) もしこれらのメソッドの一つの出力が、別のメソッドの入力として用いられることができたなら、素晴らしいであろう。 したがって、いくつかの機能を実行するために一連のこれらのメソッドをつなげることができる。 ここで示すパイプは、単語のリストを逆転、ソートし、さらに逆転し、韻を踏んでいる単語リストを作成する。

パイプ処理されたストリームがなくては、それぞれの手順の間に一時ファイルを作成しなければならない。


上記のパイプ処理されたストリームを使用した逆転とソートのメソッドを実装するプログラムを調査して、韻を踏む単語のリストを作成するために上記に示したパイプで逆転とソートのメソッドを使用する。

最初に、 RhymingWords クラスには、main() 、 reverse() sort() の3つのメソッドが含まれる。 main()メソッドはメインプログラムのコードを提供する。そしてそれは入力ファイルを開き、入力ファイル上の単語を逆転、ソート、逆転する他の2つのメソッドを使用し、そして標準出力に結果を書き込む。

reverse() sort() はパイプで使用されるように設計されている。reverse() sort の双方は、InputStream からデータを読み込み、それを処理(文字列を逆転あるいはソートする)して、別のメソッドが読みやすい PipedInputStreams を作リ出す。 詳細に reverse() を見てみる。 sort()メソッドは reverse() によく似ていて、それ自身の検討を必要としない。

public static InputStream reverse(InputStream source) {
    PipedOutputStream pos = null;
    PipedInputStream pis = null;

    try {
        DataInputStream dis = new DataInputStream(source);
        String input;

        pos = new PipedOutputStream();
        pis = new PipedInputStream(pos);
        PrintStream ps = new PrintStream(pos);

        new WriteReversedThread(ps, dis).start();

    } catch (Exception e) {
        System.out.println("RhymingWords reverse: " + e);
    }
    return pis;
}

reverse() メソッドは、逆転される文字列のリストを含む source と呼ばれる InputStream を引数として取る。reverse() は source と呼ばれる InputStream に DataInputStream をマップする。そうすると revevse()はDataInputStream のreadline()メソッドを使用してこのファイルからそれぞれの行を読むことができる。フィルタストリームで InterStream に接続(マップ)される。そして、 InputStream のデータは読み込み時にフィルタ処理される。フィルタストリームとの作業 ではこれについて説明する。)

次のにreverse() は PipedOutputStream を作成し、 PipedInputStreams をそれに接続する。 PipedOutputStream をPipedInputStreams に接続しなければならないことを覚えておくこと。reverse() は、PrintStreamをPipedOutputStream に マップする。そしてreverse()はPrintStreamのprintln()メソッドを使用して,PipedOutputStream に文字列を書くことができる。

これで reverse() WriteReversedThreadスレッドオブジェクトを作成し、このスレッドオブジェクトに PipedOutputStream に接続した PrintStream と source に接続した DataInputStream の2つのストリームを渡してこのスレッドオブジェクトを開始する。 WriteReversedThread オブジェクトは DataInputStream から単語を読み取って、それらを逆転し、PrintStream に出力を書き込む(これによって、出力をパイプに書き込む)。 スレッドオブジェクトにより、パイプの両方の端が他とは独立して実行することができ、パイプの片方の端が入出力呼び出しが完了するのを待ってブロックする時、main() メソッドがロックするのを防ぐことができる。

次は、WriteReversedThread の run メソッド である。

public void run() {
    if (ps != null && dis != null) {
        try {
            String input;
            while ((input = dis.readLine()) != null) {
                ps.println(reverseIt(input));
                ps.flush();
            }
            ps.close();
        } catch (IOException e) {
            System.out.println("WriteReversedThread run: " + e);
        }
    }
}
 

PipedOutputStream が PipedInputStreams に接続されているので、 PipedOutputStream に書かれたすべてのデータは PipedInputStreams に流れる。 データは別プログラムあるいはスレッドによって PipedInputStreams から読み取られる。 reverse() は,呼出しプログラムが使用する PipedInputStreams を返す。

sort() メソッドは reverse()メソッドと同じパターンに従う。

reverse() sort() への呼び出しは、1つのメソッドからの出力が次のメソッドの入力になるように、一緒にカスケードにされることができる。 実際は、 main() メソッドがまさにこれを行う。 韻を踏んでいる単語のリストを作成するためにreverse() sort() reverse() への呼び出しをカスケードする。

InputStream rhymedWords = reverse(sort(reverse(words)));

RhymingWords を このファイルの単語 で実行すると、次のような出力になる。

Java
interface
image
language
communicate
integrate
native
string
network
stream
program
application
animation
exception
primer
container
user
graphics
threads
tools
class
bolts
nuts
object
applet
environment
development
argument
component
input
output
anatomy
security

注意深く見てみると、environment、development、 argument、component のような「韻を踏む」単語は一緒に分類される。

参照

java.io.PipedInputStream
java.io.PipedOutputStream


Previous | Next | Trail Map | Writing Java Programs | 入出力ストリーム