第19回 入出力処理(1) 文字ストリーム



今回はキーボードからの入力とファイルへの入出力について説明します。

■java.io.Fileクラス
Fileクラスはその名の通りファイルやディレクトリ(フォルダ)に関する情報(読み取り可否、書き込み可否、ファイルサイズ等)をプロパティに格納したクラスです。

Fileのコンストラクタ
File(String path)
File(String directoryPath, String filename)
File(File directory, String filename)File(String path)
第1の形式は対象となるファイル/フォルダのフルパス名を唯一の引数であるpathに指定します。
第2の形式はフルパスを「対象ファイルを格納しているディレクトリ」名と「ファイル自体の名前」に分解し、それを文字列としてそれぞれdirectoryPathとfilenameに設定しています。
第3の形式は対象ファイルを格納するディレクトリをディレクトリ名という文字列ではなく、そのディレクトリを指す別のFileオブジェクトで指定しています。
Fileの主な変数
separatorCharパス名のディレクトリ名や
ファイル名を区切る文字
(Windowsは\、UNIXなら/)
pathSeparatorChar複数のパス名を列挙する際の区切り文字
(Windowsは;、UNIXなら:)
これらはいずれもpublic static final(全クラスから参照可能・クラス変数・値の変更不可)。
separatorCharに比べるとpathSeparatorCharの使われ方は分かりづらいかもしれませんが、第2回で環境変数を設定した際のことを思い出してください。セミコロン';'がパス同士を区切っていたはずです。
ストリームの概念図
Fileクラスのインスタンスメソッド(一部)
メソッド説明
boolean delete()ファイルを削除する
削除に成功すればtrue、失敗すればfalseを返す。
boolean existsFileオブジェクトが指しているファイルが実在すればtrueを、
そうでなければfalseを返す
String getAbsolutePath()ファイルの絶対パスを
String文字列で返す
boolean isDirectory()Fileオブジェクトが指しているのがディレクトリであればtrueを、
そうでなければfalseを返す
boolean isFile()Fileオブジェクトが指しているのがファイルであればtrueを、
そうでなければfalseを返す
boolean mkdir()Fileオブジェクトが指しているパス名で
ディレクトリを作る

■ストリームとはなにか
ストリーム(stream)とは流れを意味しますが、Javaでいうストリームとは源流(ソース:source)と行き先(デスティネーション:destination)を持ったデータの流れ道のことを指します。
ユーザからのキーボード入力を受け付け、その入力をファイル上に保存するプログラムを考えてみましょう。
ストリームの例
この図の矢印がストリームです。
ストリームには文字及び文字列の読み書きを行う為の文字ストリームと、画像等の文字では扱えないバイナリデータを扱う為のバイトストリームが存在します。

■文字ストリーム
java.ioパッケージで提供されている文字ストリームの主要なクラスの継承関係は次の通りです。
文字ストリームクラスの構成
Objectクラスのみjava.langパッケージに属しています。

■ReaderとWriter
Readerは文字や文字列の入力に、Writerは文字や文字列の出力に用いられる抽象クラスです。
Readerの主なメソッド
メソッド説明
int read()ストリームから一文字分の文字を読み出して、
その文字の文字コードを返す
boolean ready()ストリームが読み込み可ならtrue、
そうでなければfalseを返す
long skip(n)n文字分スキップして、
実際にスキップした文字数を返す

Writerの主なメソッド
メソッド説明
void write(char c)ストリームに文字cを書き込む
void close()ストリームを閉じる

その為これらのクラス自身のインスタンスを直接生成することはできませんが、ファイルやバッファ等の入力にはReaderの、出力にはWriterのサブクラスが用いられています。その為、ここに紹介するメソッドは全てそのサブクラスでも使用することができます。

■バッファ付き文字ストリーム
BufferedReaderBufferedWriterは文字ストリームへの入出力とバッファ(Buffer)と結び付けているクラスです。
バッファとは元々「間に入って衝撃をやわらげるもの」という意味がありますが、この場合はデータの入力元/出力先とコンピュータとの間に存在する記憶装置や記憶領域のことです。
ファイル読込み処理について例を挙げます。ハードディスク等の外部記憶装置にあるファイルとコンピュータと直接アクセスするのは時間がかかります。できる限りファイルとのアクセス数は少ないことが望ましいのです。
そこでコンピュータが直接ファイルとアクセスするのではなく、その間にファイル(の一部)を読み込んだ内容をバッファ内に一旦貯めておきます。コンピュータ本体はまずバッファとアクセスし、バッファが空になったら再度ファイルにアクセスするようにするのです。
このように入出力対象とコンピュータの間の緩衝材のような位置に存在するのがバッファです。
こうすることによりファイルアクセスの回数を最小限に減らすことができるため、処理効率も高くなります。
BufferedReaderはReaderクラスを拡張したクラスで、文字ストリームからの入力をバッファに格納します。
BufferedReader
コンストラクタ意味
BufferedReader(Reader r)規定サイズのバッファrを利用した
BufferedReaderオブジェクト生成
BufferedReader(Reader r, int bufSize)バッファサイズをbufSizeで指定して
BufferedReaderオブジェクト生成
独自メソッド意味
String readLine() throws IOException文字ストリームから1行分の文字列を
読み込んで返す
BufferedWriterはWriterクラスを拡張したクラスで、文字ストリームへの出力をバッファに格納します。
BufferedWriter
コンストラクタ意味
BufferedWriter(Writer w)規定サイズのバッファwを利用した
BufferedWriterオブジェクト生成
BufferedWriter(Buffer w, int bufSize)バッファサイズをbufSizeで指定して
BufferedWriterオブジェクト生成
独自メソッド意味
void newLine() throws IOException改行文字を出力する
独自メソッドがスローする例外java.io.IOExceptionは検査例外です。これらのメソッドを使う際は例外処理を行わないとコンパイルエラーになります。

■バイトストリームとの変換
InputStreamReaderOutputStreamWriterは文字ストリームとバイトストリームの間を仲立ちするクラスです。
InputStreamReaderはReaderクラスを拡張したクラスで、バイトストリームを文字ストリームに変換します。
InputStreamReader
コンストラクタ意味
InputStreamReader(InputStream is)ユーザマシン規定の文字セットを使用した
InputStreamReaderオブジェクト生成
InputStreamReader
(InputStreamReader isr, String charSetName)
文字セットをcharSetNameに指定して
InputStreamReaderオブジェクト生成
独自メソッド意味
String getEncoding()使われている文字セットを返す
OutputStreamWriterはWriterクラスを拡張したクラスで、文字ストリームへの出力をバッファに格納します。
OutputStreamWriter
コンストラクタ意味
OutputStreamWriter(OutputStream os)ユーザマシン規定の文字セットを使用した
OutputStreamWriterオブジェクト生成
OutputStreamWriter
(OutputStream os, String charSetName)
文字セットをcharSetNameに指定して
OutputStreamWriterオブジェクト生成
独自メソッド意味
String getEncoding()使われている文字セットを返す


■入力を受け付ける方法
System.inはInputStream型の標準入力ストリームです。標準入力は普通キーボード入力ですが、環境やユーザ側の操作により切り替えることもできます。
このストリームは既に開いており、ここから入力されたデータを受け取ることができます。ですがSystem.in で返されるデータは文字データではなく純粋なバイトデータなので、これを文字データに変換する必要があります。この時用いられるのがInputStreamReader クラスです。
InputStreamReader isr =
                  new InputStreamReader(System.in);
この文を実行するとコマンドプロンプトはキーからの入力を待つ状態となります。但しこれでは入力を1文字1文字別々に扱っていく為、効率が良くありません。
そこで効率を上げるために1行ずつ読みこむようにします。
InputStreamReader isr =
                  new InputStreamReader(System.in);
BufferedReader br =                   new BufferedReader(isr);
こうすることでBufferedReaderクラスオブジェクトはデータを一時的に保持しておき、リターンキーが押されると値を返します。
BufferedReaderから入力された文字列を受け取りたい場合はBufferedReaderクラスのインスタンスメソッドreadLine()を使用します。
String str = br.readLine();
これにより、改行までの1行分文字列のデータがstrに格納できます。
これらをまとめて次のように記述することもできます。
BufferedReader br = new BufferedReader
                    (new InputStreamReader(System.in));String str = br.readLine();


■ファイルからの文字入力/ファイルへの文字出力
FileReaderはInputStreamReaderを拡張したクラスで、ファイルから文字を入力します。
FileReader
コンストラクタ意味
FileReader(String filepath)
throws FileNotFoundException
パス名filepathでFileReaderオブジェクト生成
FileReader(File fileobj)
throws FileNotFoundException
対象ファイルをFileオブジェクトfileobjで指定して
FileReaderオブジェクト生成
独自メソッド意味
なし。InputStreamReader,Readerから継承された
メソッドを使用可能。
FileWriterはOutputStreamWriterを拡張したクラスで、ファイルへ文字を出力します。
FileWriter
コンストラクタ意味
FileWriter(String filepath)
throws FileNotFoundException
パス名filepathでFileWriterオブジェクト生成
FileWriter
(String filepath, boolean append)
throws FileNotFoundException
パス名filepathでFileWriterオブジェクト生成
ファイルが既存でappendがtrueなら追加更新
FileWriter(File fileobj)
throws FileNotFoundException
対象ファイルをFileオブジェクトfileobjで指定して
FileWriterオブジェクト生成
独自メソッド意味
なし。OutputStreamWriter,Writerから継承された
メソッドを使用可能。
FileNotFoundExceptionはIOExceptionのサブクラスであり、検査例外です。その為IOException同様、これらをスローするメソッドを使用する場合は例外処理を記述しないとコンパイルエラーになります。

■PrintWriter
PrintWriterはWriterを拡張したクラスで、基本データ型やオブジェクト文字列をファイルに出力します。
PrintWriter
コンストラクタ意味
PrintWriter(OutputStream outputStream)指定outputStreamでPrintWriterオブジェクト生成
PrintWriter
(OutputStream outputStream,
boolean autoFlush)
指定outputStreamでPrintWriterオブジェクト生成
autoFlushがtrueなら行の自動フラッシュを行う
PrintWriter(Writer writer)指定writerでPrintWriterオブジェクト生成
PrintWriter
(Writer writer, boolean autoFlush)
指定writerでPrintWriterオブジェクト生成
autoFlushがtrueなら行の自動フラッシュを行う
独自メソッド意味
PrintWriter append(char c)指定文字cを追加して返す
void print(boolean b)
void print(char c)
void print(char[] s)
void print(double d)
void print(float f)
void print(int i)
void print(long l)
void print(Object obj)
引数を文字列化してファイルに出力
void close()ストリームを閉じる

■サンプルプログラム
FileWriterを用いたファイルへの出力処理プログラムです。
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterTest extends java.lang.Object{
    public static void main (String [] args){
        FileWriter fw            = null;
        String     strFileName   = "C:\\Temp\\Test.txt";//\\=エスケープ文字
        char       charBuffer2[] = { 'L', 'I', 'N', 'E', '2', '\n' };
        String     strLine3      = "これが3行目";
        
        try{
            System.out.println("処理を開始します。");
            System.out.println("strFileName = " + strFileName);
            
            //FileWriterオブジェクトを生成する(追加フラグ=false)
            fw = new FileWriter(strFileName, false);
            
            //FileWriterオブジェクトを使ってファイルに書き込みを行う
            //書き込みに使うのはスーパークラスWriterで定義されている
            //write()メソッド
            fw.write('A');           //void write(int c)
            fw.write('\n');          //void write(int c)
            
            //ここで一旦FileWriterオブジェクトを閉じる
            fw.close();
            fw = null;
            
            //再度FileWriterオブジェクトを生成(追加フラグ=true)
            fw = new FileWriter(strFileName, true);
            
            //write()メソッドで再度書き込みを行う
            fw.write(charBuffer2);   //void write(char buffer[])
            fw.write(strLine3);      //void write(String s)
            
            //再度FileWriterオブジェクトを閉じる
            fw.close();
        }
        catch (IOException e){
            System.out.println("IOExceptionが発生しました。");
            System.out.println(e);
        }
        catch (Exception e){
            System.out.println("例外が発生しました。");
            System.out.println(e);
        }
        finally{
            System.out.println("処理終了しました。");
        }
    }
}
これをBufferedReaderを用いた形で書き直すと次のようになります。
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;

public class BufferedWriterTest extends java.lang.Object{
    public static void main (String [] args){
        FileWriter     fw            = null;
        BufferedWriter bw            = null;
        String         strFileName   = "C:\\Temp\\Test2.txt";
        char           charBuffer2[] = { 'L', 'I', 'N', 'E', '2', '\n' };
        String         strLine3      = "これが3行目";
        
        try{
            System.out.println("処理を開始します。");
            System.out.println("strFileName = " + strFileName);
            
            //FileWriterオブジェクトを生成(追加フラグ=false)
            fw = new FileWriter(strFileName, false);
            
            //FileWriterオブジェクトを使用してBufferedWriterオブジェクトを生成
            bw = new BufferedWriter (fw);
            
            //BufferedWriterオブジェクトを使ってファイルに書き込みを行う
            //書き込みに使うのはスーパークラスWriterで定義されている
            //write()メソッド
            bw.write('A');           //void write(int c)
            bw.write('\n');          //void write(int c)
            bw.write(charBuffer2);   //void write(char buffer[])
            bw.write(strLine3);      //void write(String s)
            
            //BufferedWriterオブジェクトを閉じる
            bw.close();
        }
        catch (IOException e){
            System.out.println("IOExceptionが発生しました。");
            System.out.println(e);
        }
        catch (Exception e){
            System.out.println("例外が発生しました。");
            System.out.println(e);
        }
        finally{
            System.out.println("処理終了しました。");
        }
    }
}
FileWriterと異なりBufferedWriterのコンストラクタには指定ファイルが既存の場合追記を行うか否かを指定するappendを引数にとるものがない為、書き込みを中断して再開することがない形に改めています。
最後に、InputStreamReaderとBufferedReaderを用いてキーボードからの入力を受け付けて変数に格納するサンプルプログラムです。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class KeyboardInputTest extends java.lang.Object{
    public static void main(String args[]){
        try{
            System.out.println("名前を入力してください。");
            BufferedReader br =
            new BufferedReader(new InputStreamReader(System.in));
            String name = br.readLine();
            System.out.println("ようこそ、" + name +"さん。");
        }catch (IOException e){
            System.out.println("IOException発生。");
            System.out.println(e);
        }
        catch (Exception e){
            System.out.println("Exception発生。");
            System.out.println(e);
        }
        finally{
            System.out.println("処理を終了します。");
        }
    }
}

次回はバイナリデータの入出力を行うバイトストリームについて説明します。

質問はこちらへお願いします(件名はそのままで)。