ファイル入出力

ファイルの入出力

WWW browser の中で動く appletについては,security の観点から,file への入出力は許されていません。

ファイルからの入力とファイルへの出力は次のようにします。

import java.io.*;
class Test {
    public static void main(String args[]) {
        try {
            InputStream input
                = new FileInputStream("foo.txt");  // 入力ファイルを開く
            OutputStream output
                = new FileOutputStream("bar.txt"); // 出力ファイルを開く
            int c;
            while ((c = input.read()) != -1)       // 入力
                output.write(c);                   // 出力
            input.close();          // 入力ファイルを閉じる
            output.close();         // 出力ファイルを閉じる
        } catch (IOException e) {   // 入出力エラーをつかまえる
            System.err.println(e);  // エラーメッセージ出力
            System.exit(1);         // 終了コード 1 で終了する
        }
    }
}

これは,foo.txt というファイルを読んで, 内容をそのまま bar.txt というファイルに書き出すプログラムです。

もし foo.txt が存在しないと, 15行目の System.err.println(e); が

    java.io.FileNotFoundException: foo.txt
と出力して止まってしまいます。 また,もし bar.txt があると,それに上書きしてしまいますので, 気をつけてください。

上のプログラムで,

    InputStream input;
    input = new FileInputStream("foo.txt");
としていますね。これは本当は
    FileInputStream input;
    input = new FileInputStream("foo.txt");
と書くべきだと思われるかもしれません。もちろんそう書いてもいいのですが, FileInputStream は InputStream の子クラスですので, より一般的な InputStream 型の変数 input を作って, それに FileInputStream クラスのインスタンスを代入しても かまわないのです。ただしこれは, 親クラスが子クラスと同じ名前・引数のメソッドを持つ場合だけです。 子クラスの親クラスにない名前のメソッドを使いたい場合は, ちゃんと子クラスの型の変数に代入しなければなりません。

ファイルの入出力(バッファあり)

上のプログラムは,ディスクから1文字(1バイト)ずつ 読み書きしていますので,あまり能率的ではありません。 上の

            InputStream input
                = new FileInputStream("foo.txt");  // 入力ファイルを開く
            OutputStream output
                = new FileOutputStream("bar.txt"); // 出力ファイルを開く
のところを
            InputStream input
                = new BufferedInputStream(
                      new FileInputStream("foo.txt"));
            OutputStream output
                = new BufferedOutputStream(
                      new FileOutputStream("bar.txt"));
とするだけで,ずいぶんプログラムの実行速度が上がります。 これはバッファリングの効果です。

バッファ(buffer)とは一般に「緩衝(かんしょう)装置」つまり 二つのものの間にはさまって衝撃を和らげるもののことです。

ファイルからの入力の場合は, 1バイトずつディスクから読むと時間がかかるので, 一度にたとえば512バイト読み込んでメモリの一部(バッファ)に保存しておき, 2度目からは実際に読むのではなくメモリからコピーしてくることを意味します。

ファイルへの出力も同様で, 最初は実際に書き込まずバッファに保存しておき, たとえば512バイトになると一気に書き出します。

バッファを使うことをバッファリング(buffering)するともいいます。

バッファリングしているときは,最後の文字を書き出したつもりでも, 実際には端数分がメモリに残っています。 この端数分は, 出力ファイルをクローズした(閉じた)時点でディスクに書き込まれます。 つまり,output.close() を実行した時点で書き込まれます。 クローズを忘れると,ファイルが全部書きおわらないうちに終了して しまうことがありますので,必ずオープンしたらクローズする習慣をつけましょう。

さらに高度な入出力

上のプログラムをさらに

            DataInputStream input
                = new DataInputStream(
                      new BufferedInputStream(
                          new FileInputStream("foo.txt")));
            PrintStream output
                = new PrintStream(
                      new BufferedOutputStream(
                          new FileOutputStream("bar.txt")));
とすると,入力では readLine(), 出力では println() のような便利なメソッドが使えるようになります。 たとえば
            String s;
            while ((s = input.readLine()) != null)
                output.println(s);
のようなことができます。 readLine() は,ファイルの終わりまで読み尽くした後では, null という特別な値を返します。これが返ってきたら, 繰返しを終了します。