プログラミング応用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)に示す。



次へ進む

戻る