プログラミング応用b 第5回 『ファイル入出力の基礎1』 - 3. バイトデータ入力系ストリーム |
では,「バイトデータ入力系ストリーム」から説明する。
■3.1 バイトデータ入力系統ストリームの関連クラス群
最初に,下図Fig.2のバイトデータ入力ストリーム系のクラス群を見てみよう。(下図をクリックすると授業で扱わないクラスは非表示になる)
■3.2 スーパークラスInputStream
まず,バイトデータ入力ストリーム系のスーパークラスとして,InputStreamがある。
InputStreamは,バイトデータ用の入力ストリームが備えるべき基本的なメソッドを定義
している抽象クラスである。これらのメソッドを下表Table 1に示す。
重要なメソッドとしては,開いたストリームをクローズするclose( ),ストリームからバイト
データを読み込む3つのread( )がある。引数無しのread( )メソッドは読み込みに成功すると,
読み込んだバイトデータ(1バイトのbyte型データ)を4バイトのint型データの末尾に格納し,
int型データとして返す(下図(1))。もし,ストリームの終端に達して読み込みに失敗すると,整数値
-1を返す(下図(2))。
その他,入力データを指定した数だけ読み飛ばすメソッドskip( )もある。
また,バイトデータ入力ストリームによっては,マーク機能を持つものもある。これらマーク
機能に関するメソッドもInputStreamクラスで定義されている。
コラム マーク機能とは,ストリームからデータを入力しているとき,マークを設定すると,後でそのマーク位置 まで戻って再びデータを再入力できるようにする機能である。mark( )メソッドを呼び出すと,現在の読み 込み位置にマークが設定される。そして,reset( )メソッドを呼び出すと,最後に設定したマーク位置まで 読み込み位置が戻され,そこから再度読み込みが開始される。 実際には,マークを設定した時点からreset( )が呼び出されるまでに入力したデータをストリームオブジェ クトが保存しておくことで,このマーク機能は実現されている。最大どれだけのデータを憶えておくように するか指定できるmark( )メソッドも用意されている。すべてのストリームでマーク機能が使えるわけではな く,マーク機能を持っているストリームでは,markSupported( )メソッドがtrueを返すようになっている。 |
■3.3 バイト入力用の基本ストリーム
では,Fig.2にもどって,今度はInputStreamのサブクラスを見てみよう。Fig.2を再掲する。(下図をクリックすると授業で扱わないクラスは非表示になる)
InputStream のサブクラスは,2つのグループわけられる。ひとつは,本当の意味でのストリ
ームで,ここでは便宜的に“基本ストリーム”と呼ぶことにする。もうひとつのグループは,
他のストリームに付加機能をつけるためのストリームで,ここで便宜的にラッパストリームと呼
ぶことにする。
バイトデータ入力ストリーム系の基本ストリームとしては, ByteArrayInputStream, FileInputStream,
PipedInputStream の3つがあることが上図で分かる。このうち,授業で扱う FileInputStream に関して
のみ次に説明する。
○FileInputStream
FileInputStream は,ファイルからのバイトデータの読み込みを行う入力ストリームである。
主なコンストラクタとメソッドをTable 2-(2)に示す。コンストラクタの引数に使われるクラス
File は,ファイルを操作するためのユーティリティ(道具)を集めたクラスである。また,クラス
FileDescriptor は,特定のファイルを指定するファイル記述子と呼ばれるものである。ファイル
パス名の他に,これらを使ってファイルを指定・オープンすることも可能になっている。
また, getChannel( ) は,JDK1.4で導入された新しい入出力の仕組みで,ストリームのかわり
に使われるチャンネル(channel)を生成するメソッドである。この新しい入出力は java.nio パッ
ケージにまとめられている。実は現在では,チャンネルを入出力に使うのが推奨されているが,
Java誕生時より用意されており,未だによく使われているストリームの方を本授業では解説する。
(興味が有れば是非チャンネルについても自分で調べてみよ)
■3.4 バイト入力用のラッパストリームとその仕組み
前述のように,ラッパストリームとは,他のストリームに付加機能をつけるストリームである。
素のままのストリームは,利用者オブジェクトから read( ) メソッドを呼ばれることで外界から
入力されたデータを利用者オブジェクトに送り, close( ) メソッドを呼ばれることでストリーム
を閉じる(下図Fig.3-(1))。
ラッパストリームが元になるストリームに機能を付加する仕組みを上図Fig.3-(2)に示す。
まず,元になるストリームオブジェクトをラッパストリームオブジェクトが参照している。
そして,ラッパストリームのメソッドは,元のストリームのメソッドを呼び出している。
たとえば,
・ある利用者オブジェクトのメソッドが,ラッパストリームの read( ) メソッドを呼び出すと(Fig.3-①),ラッパストリームの read( ) メソッドは,
参照している元のストリームの read( ) メソッドを呼び出す(Fig.3-②)。元のストリームの read( ) メソッドは,ストリームからデータ
を取り出し(Fig.3-③),それを呼び出し元であるラッパストリームの read( ) メソッドに返す(Fig.3-④)。ラッパストリームの read( ) メソッドは,
返された入力データを呼び出し元のメソッドに返す(Fig.3-⑤)。
・同様に,利用者オブジェクトのメソッドがラッパストリームの close( ) メソッドを呼ぶと(Fig.3-⑥),間接的に元のストリームの close( ) メソッドが
呼ばれることになる(Fig.3-⑦)。
このような仕組みによって,利用者オブジェクトにとっては,ラッパストリームが元のスト
リームを“包んで(wrap)”いるように見える。そのために,ラッパ(wrapper stream)ストリーム
と呼ぶのである。一般に,このラッパストリームクラスのように,他のクラスをラップする
クラスをラッパクラスとか,単にラッパと呼ぶ。なお,当然のなりゆきとして,ラッパス
トリームは元のストリームを引数とするコンストラクタを持つことになる。
そして,ラッパストリームは,元のストリームのメソッドを呼びながら,様々な追加処理
を行う機会を持つことができる。たとえば,Fig.3のラッパストリームの read( ) メソッドは,
元のストリームの read( ) メソッドが返してきたデータになにかしらの加工を施して,利用者
オブジェクトに加工結果のデータを返すように定義することが可能である。
つまり,利用者オブジェクトからすれば,このラッパストリームは,元のデータストリーム
に特定のデータ加工機能を付加したものに見えるということである。たとえば,暗号化された
データを復号化するラッパストリームを考えることが出来る(下図)。
このラッパストリームによる機能追加の仕掛けは,入力ストリームに対してだけではなく,
出力ストリームにも有効である。
では,Fig.2でふたたびバイト入力用のラッパストリーム群を見ていくことにしよう。バイト
入力用のラッパストリーム群には, InputStream をラップするラッパストリームとして,
・FilterInputStream
とそのサブクラスである
・DataInputStream
・BufferedInputStream
・PushbackInputStream
と,そのInputStreamの直接のサブクラスである
・ObjectInputStream
・SequenceInputStream
の計6個が用意されている。授業では,これらのうち最初の3つのクラス FilterInputStream,
DataInputStream, BufferedInputStream のみ扱う。まず,FilterInputStream から説明しよう。
○FilterInputStream
FilterInputStreamは,まさに元ストリームから入力するデータを加工(filtering)することを
目的としたラッパストリームである。元になる InputStream 型ストリームを引数とするコンス
トラクタを持っている(Table 2-(3))。
FilterInputStream 自身は何も加工を行わないが,サブクラスのためにデータ加工のための骨
組みをあたえている。そして,実際に様々な加工をするように定義されているのが,3つのサブ
クラス
・DataInputStream
・BufferedInputStream
・PushbackInputStream
である。
○DataInputStream
DataInputStreamは,主にプリミティブ型(基本型)を中心としたデータ値をストリームから
読み込む機能を,元のストリームに付加するラッパクラスである。そのため,プリミティブ型
を中心としたデータ値を読み込むためのメソッドを集めたインタフェイス DataInput を実装
している。
インタフェイス DataInput の詳細を,下表Table 3に示す。その他,コンストラクタや独自
のメソッドを,Table 2-(4)に示す。
○BufferedInputStream
BufferedInputStream は,元の入力ストリームにバッファ機能を付加するラッパクラスであ
る。ディスク装置などの入出力機器のデータアクセス速度は,メモリ上のデータへのアクセス
速度にくらべ,圧倒的に遅い。そのため,少量のデータを頻繁に読み込むなどすると,非常に
時間がかかってしまう(下図(1))。
そこで,バッファ(buffer)と呼ばれるメモリ上の領域に,まとまった量のデータをあらかじめ一期に読み込んでおき,
実際に読み込むときには,そのバッファからデータを入力するようにすれば,入力処理を高速化することができる(上図(2))。
BufferedInputStream オブジェクトは,バッファ領域を確保して,バッファ機能を提供してくれるのである。
積極的に使うべきラッパストリームと言える。コンストラクタをTable 2-(5)に示す。