Revised: Mar./16th/2002
UNIX 系 OS では、テキストファイルの中味を見たり、複数のテキストファイルを一つにつなげて出力する為のコマンドが用意されています。このコマンドは cat
コマンド (conCATenate) と呼ばれています。 Java でも、複数のストリームをつなげるクラスが用意されています。
SequenceInputStream
は複数の入力ストリームから一つの入力ストリームを作ります。
継承階層:
java.lang.Object | +--java.io.InputStream | +--java.io.SequenceInputStream
コンストラクタ:
SequenceInputStream(Enumeration e) SequenceInputStream(InputStream s1, InputStream s2)
二つの InputStream
型のオブジェクトを連結するのが基本的な使い方です。三つ以上のストリームの連結には java.util.Enumeration
(列挙)インタフェースを使います。このインタフェースを実装 (implements) したクラス型のオブジェクトは、一連の要素を列挙として参照し、次のメソッドが使えるようになります:
boolean | hasMoreElements() |
列挙にさらに要素があるかどうかを判定します。 |
---|---|---|
Object | nextElement() |
列挙に 1 つ以上の要素が残っている場合は、次の要素を返します。 |
ここでは UNIX 系 OS の cat
コマンドの再現をしてみましょう。コマンドライン引数で与えられたパスの列挙を連結して標準出力に出力します。
Enumeration
の実装を作るEnumeration
のサンプルコンストラクタでは、文字列の配列で受け取った引数から、InputStream
オブジェクトの列挙をつくり、インタフェースのメソッドを実装します。
このクラスが満たすべき条件は次のようにまとめられます。
Enumeration
インタフェースの実装public Object nextElement()
NoSuchElementException
public boolean hasMoreElements()
true
SequenceInputStream
クラスの要求Enumeration
型Enumeration
は「実行時の型」が InputStream
「実行時の型」とは、 nextElement()
の戻り値のことですが、インタフェースでは、全てのクラスのスーパークラスである Object
型が指定されているので、任意のクラス型が許されます。また、 SequenceInputStream
クラスの要求である InputStream
クラスは全てのバイトストリームクラスのスーパークラスなので、任意のバイトストリームが許されます。このサンプルではファイルを扱うので、実際に作成するのは FileInputStream
です。
まとめると、代入の自動型変換は次のようになっています。
[InputStream] = [FileInputStream] [Object] = [InputStream]
FilesList.java
:
import java.io.*; import java.util.*; class FilesList implements Enumeration { private String[] files; private int counter = 0; FilesList(String[] args) { files = args; } // 要素が残っていれば true public boolean hasMoreElements() { if (counter < files.length) { return true; } else { return false; } } // 次の要素を返す public Object nextElement() { InputStream in = null; // 次の要素が無ければ例外 if (!hasMoreElements()) { throw new NoSuchElementException("ファイル終了!"); } else { String retFile = files[counter]; counter++; try { in = new FileInputStream(retFile); } catch (IOException e) { System.err.println(files[counter] + ": 処理できない!"); } } // InputStream 型の参照を返す return in; } }
つぎはこのクラス FilesList
を利用する main()
メソッドを作ってみます。引数に複数の文字列を受け取って、この配列の参照を上のクラスのコンストラクタ引数に与えます。
Cat.java
:
import java.io.*;
class Cat {
public static void main(String[] args) throws IOException {
FilesList files = new FilesList(args);
SequenceInputStream in = new SequenceInputStream(files);
BufferedReader bin
= new BufferedReader(new InputStreamReader(in));
String str="";
while ((str = bin.readLine()) != null) {
System.out.println(str);
}
bin.close();
in.close();
}
}
まず、上で作った FilesList
クラスをインスタンス化し、これを引数として SequenceInputStream
を作っています。
さらにこれを BufferedReader
クラスでラップしています。 SequenceInputStream
型のストリームはバイトストリームなので、文字ストリームに変換する為に、 InputStreamReader
を間に挟んでいます。
あとは readLine()
で行を読み込んで出力しています。
実行結果:
C:\IO>javac FilesList.java C:\IO>javac Cat.java C:\IO>java Cat test.txt test2.txt test3.txt Hello World. Bye World. こんにちは さようなら Buongiorno. Arrivederci. C:\IO>
test.txt
Hello World. Bye World.
test2.txt
こんにちは さようなら
test3.txt
Buongiorno. Arrivederci.