ファイル入出力の基本
ファイルに対して、ある処理の結果を書き込んだり、何らかのデータを読みとったりすることは、実際のアプリケーションにおいては、非常によく用いられる処理です。
ここでは、このようなファイル入出力のプログラムを、ストリームを用いて行う処理の基本例として、解説することにします。
なおファイル処理は、プログラムを実行するハードウェアに依存する部分があります。まずはWindows上で動作確認できるサンプルで一般的な説明を行い、記事の後半で、Andoridでのプログラム例を説明します。
ファイルからの入力
最初にファイルの入力処理です。ファイルでは、文字でもバイナリでもあつかえますが、今回は文字ストリームを用いたテキストファイルの例を見ていきましょう。
次のサンプルコードは、sample1.txtというテキストファイルを1行ずつ読み込み、標準出力に書きだす例です。
try { File f = new File("sample1.txt"); // (1) FileReader fr = new FileReader(f); // (2) BufferedReader br = new BufferedReader(fr); // (3) String line; try { // 1行ずつファイルの最後まで読み込む while ((line = br.readLine()) != null) { // (4) System.out.println(line); } } finally { br.close(); // (5) } } catch (IOException e) { // ファイルがない等のエラーがあった場合の処理 }
-
Fileオブジェクトの生成
java.io.Fileクラスは、ファイルやディレクトリを操作するためのクラスです。ファイルやディレクトリの生成や存在確認、アクセス権や名称の調査など、さまざなメソッドが用意されています。ここでは、ファイル名を引数としてFileオブジェクトを生成しています。
-
FileReaderオブジェクトの生成
java.io.FileReaderクラスは、実際にファイルをオープンして文字を読み込むストリームクラスです。この例では、コンストラクタにFileオブジェクトを指定していますが、直接ファイル名を渡すことも可能です。その場合は、Fileクラスは不要です。
-
BufferedReaderオブジェクトの生成
java.io.BufferedReaderクラスは、FileReaderオブジェクトのデータを一時的に保持するクラスで、プログラムとの橋渡しとなるストリームクラスです。つまりファイルからのデータは、2つのストリームをたどるということです。ストリームオブジェクトは、少なくともひとつは必要ですが、このように連結することもできます。APIには、いろいろな処理に応じたストリームクラスが用意されています。なお、この例のファイルの読み込み処理は、BufferdReaderクラスを経由しないでも実現可能です。ただファイルやネットワーク通信のように、アクセスに少し時間がかかるデータに対しては、一時的にデータを蓄える(バッファ)ストリームオブジェクトを利用するのが通常です。バッファを介することで、物理的なアクセス回数が減り、プログラムの処理が速くなるからです。
-
BufferdReaderのreadLine(またはread)メソッドで読み込む
BufferedReaderクラスのreadLineメソッドは、改行文字(¥n)、復帰文字(¥r)、復帰改行文字(¥r¥n)のいずれかまでを1行とするテキストを読み込み、文字列として返します。結果の文字列には、終端の文字は含まれません。また、ストリームの終わりを検出すると、nullを返します。もうひとつの読み込みメソッドであるreadメソッドは、1文字単位でデータを読み込む場合に利用します。
-
各オブジェクトの終了処理
Javaでは、オブジェクトの破棄はガベージコレクションにより自動で行われます。明示的に終了処理を記述する必要がないため、ストリームのクローズ処理も忘れがちになります。もちろんストリームオブジェクトが破棄されるときにクローズされるのですが、ストリームに関しては、使用時のみオープンして、使用後は速やかに閉じるのが基本です。このサンプルでは、BufferedReaderオブジェクトのcloseメソッドのみ呼んでいます。BufferedReaderオブジェクトは、FileReaderオブジェクトを引数として生成しています。つまり、連結されたストリームオブジェクトは、数珠つなぎになっているのです。最後のストリームオブジェクトをクローズすることで、連結されたストリームすべてがクローズされ、その過程でファイルも解放されることになります。なお、closeメソッドの呼び出しは、finallyブロックに記述するようにしましょう。これは、ファイルの読み込み中に例外が発生した場合でも、クローズ処理が漏れないようにするためです。
文字コードの指定
このようにFileReaderクラスは、お手軽に利用できるクラスですが、残念な面もあるクラスです。それは、明示的に文字コードを指定して読み込めないところです。
FileReaderクラスでは、Java仮想マシンのデフォルト・エンコーディングにしか対応していないため、日本語などで文字化けが発生する場合があります。文字コードを指定してテキストファイルを読み込みたい場合には、FileReaderクラスの代わりに、バイト単位のストリームクラス、FileInputStreamクラスとInputStreamReaderクラスを組み合わせます。
例えば、Windowsで用いられる文字コード、Windows-31Jのテキストファイルであれば、次のようになります。InputStreamReaderの第2引数に、文字コードを指定します。
InputStreamReader isr = new InputStreamReader( new FileInputStream(f), "Windows-31J"); // (2) BufferedReader br = new BufferedReader(isr); // (3)
ファイルへの出力
テキストファイルに出力する基本的な手順は、入力処理と同じような手順になります。Fileオブジェクトを生成した後、FileWriter(またはOutputStreamWriterとFileOutputStreamのペア)とBufferedWriterのオブジェクトを生成します。そして、BufferedWriterクラスのwriteメソッドを呼び出して、データを書きだします。
具体的な例は、次のAndoridで動作するサンプルで紹介することにしましょう。