ここでは、ファイルからの読み込み(InputStream)を取り上げて話を進めます。書き込み(OutputStream)の紹介は省略しますが、読み込み側の仕組みをしっかりと理解すれば、その応用で理解できると考えます。
実行時のカレントディレクトリに今回のサンプルで利用する「sampledata.txtファイル」を準備しておいてください。このファイルからデータを読み込むものとして話を進めます。このファイルには、下記のような内容が格納されていることとします。
それでは、実際にファイルをバイト入力ストリームで読み込むサンプルを書いてみましょう。
図9 ファイルをバイト入力ストリームで読み込む
java.io.FileInputStreamクラスはファイルからの読み込みをバイト入力ストリームとして提供します。この例では、FileInputStreamのインスタンスはjava.io.InputStreamで受けて以降の処理を行います。
なお、ここで登場するユーティリティクラス(HexStringUtil.java)は、前回の連載記事のものを利用することとします。
極めて原始的なInputStream利用例(※注意:このサンプルは説明のための途中版ですバッファリングが行われていません) |
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class InputStreamSample01 {
public static void main(final String[] args) {
try {
new InputStreamSample01().process();
} catch (IOException e) {e.printStackTrace();}
}
public void process() throws IOException {
final InputStream inStream
= new FileInputStream("sampledata.txt");
try {
for (;;) {
final int readChar = inStream.read();
//Streamの終わりに達して読み込むデータがない場合
if (readChar < 0) break;
// 16進表記で画面出力
System.out.println(HexStringUtil.
byteToHexString((byte) readChar));
}
} finally {
if (inStream != null) inStream.close();
}
}
} |
|
ここで書かれているソースコードには問題が含まれています。バッファリングをわざと行わずにコーディングしています。この書き方だと、readメソッドを呼び出すたびにOSのファイル読み込み機能が実行されてしまいます。そのような状況は、多くの場合望ましくありません。このため、実際のプログラミングの場合には、後述のようにバッファリングを行ったプログラミングを行います。
なお、このプログラムをsampledata.txtファイルが存在しない状態で実行すると、以下のような例外が発生して処理が中断します。該当の名称のファイルが存在するようにしてから再度実行してください。
java.io.FileNotFoundException: sampledata.txt (指定されたファイルが見つかりません。) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.(Unknown Source) at java.io.FileInputStream.(Unknown Source) at InputStreamSample01.process(InputStreamSample01.java:20) at InputStreamSample01.main(InputStreamSample01.java:13)
現実的なプログラミングでは、バッファリングしてバイト入力ストリーム読み込みを行います。
図10 ファイルをバイト入力ストリームで読み込む(バッファリング付き)
java.io.FileInputStreamで得られたバイト入力ストリームをjava.io.BufferedInputStreamクラスのコンストラクタで受け取って、バッファリング読み込み付きのバイト入力ストリームに変えて、このインスタンスをjava.io.InputStreamで受けて、以降の処理を行います。
このようにバッファリング付きのバイト入力ストリームにすることにより、readメソッドを呼び出すごとにOSのファイル読み込みが実行されることを、防ぐことができます。
今回の例では、BufferedInputStreamのバッファサイズはデフォルト値を使うコーディングを行っています。バッファサイズを変更したい場合には、バッファサイズを指定できるBufferedInputStreamクラスのコンストラクタを呼び出すように、変更します。
バッファリングを行ったInputStream利用例 |
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class InputStreamSample02 {
public static void main(final String[] args) {
try {
new InputStreamSample02().process();
} catch (IOException e) {e.printStackTrace();}
}
public void process() throws IOException {
final InputStream inStream = new BufferedInputStream(
new FileInputStream("sampledata.txt"));
try {
……省略……
}
}
} |
|
ここでは、バッファ付き読み込みを行いましたが、このようなバッファを用いた入出力はコンピュータ技術で重要なものの1つです。ぜひ、しっかりと理解しておきましょう。
次に、文字ストリームを使って読み込む例を見ていきます。ここでは、バイトストリームから文字ストリームへ文字エンコーディング指定付きで変換する例を取り上げます。
編集部注:文字コード・文字エンコーディングについて詳しく知りたい読者は前回記事をご参照ください。
図11 ファイルを文字入力ストリームで読み込む
java.io.FileInputStreamで得られたバイト入力ストリームをjava.io.BufferedInputStreamのコンストラクタで受け取ってバッファリング読み込み付きのバイト入力ストリームに変え、それをjava.io.InputStreamReaderクラスのコンストラクタを文字エンコーディング指定付きで呼び出して文字入力ストリームへと変換しています。この文字入力ストリームのインスタンスをjava.io.Readerクラスで受けて、以降の処理を行っています。
原始的なReaderの利用例 |
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
public class ReaderSample01 {
public static void main(final String[] args) {
try {
new ReaderSample01().process();
} catch (IOException e) {e.printStackTrace();}
}
public void process() throws IOException {
final Reader reader = new InputStreamReader(
new BufferedInputStream(new FileInputStream(
"sampledata.txt")), "Shift_JIS");
try {
for (;;) {
final int readChar = reader.read();
//Streamの終わりに達して読み込むデータがない場合
if (readChar < 0) break;
// charとして画面出力
System.out.println((char) readChar);
}
} finally {
if (reader != null)
reader.close();
}
}
} |
|
実際には、文字入力ストリームはjava.io.BufferedReaderクラスを利用して実現する場合が多くなります。このBufferedReaderを利用した文字入力ストリームの例を見ていきます。
java.io.FileInputStreamで得られたバイト入力ストリームをjava.io.InputStreamReaderクラスのコンストラクタを文字エンコーディング指定付きで呼び出して文字入力ストリームへと変換し、そのインスタンスをjava.io.BufferedReaderクラスのコンストラクタで受けてバッファリング付きの文字入力ストリームにしています。この文字入力ストリームのインスタンスをjava.io.Readerクラスで受けて、以降の処理を行っています。
BufferedReaderクラスはバッファリング読み込みを実現するほかにも、文字入力ストリームを読み込むための便利なメソッドが提供されているので、よく利用されるものの1つです。
なお、BufferedReaderによってバッファリング読み込みを実現しているので、これまでの例で利用していたjava.io.BufferedInputStreamはコンストラクタの連鎖から取り除いてあります。
図12 ファイルを文字入力ストリームで読み込む(バッファリング付き)
バッファリングを行ったReaderの利用例 |
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class ReaderSample02 {
public static void main(final String[] args) {
try {
new ReaderSample02().process();
} catch (IOException e) {e.printStackTrace();}
}
public void process() throws IOException {
final BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(
"sampledata.txt"), "Shift_JIS"));
try {
……省略……
}
} |
|
次ページからは、前述のエクスプローラのようなファイル操作をプログラムで実現する方法を見ていきましょう。