Java によるテキストファイルの読み込みと書き込み
ここではテキストファイルから文字を読み込む方法をいろいろとみていきましょう。
読み込んだデータは、標準の出力へ書き出します。
Java の FileInputStream によるテキストデータの読み込み
Java ではテキストファイルからデータを読む方法として、いろいろな方法があります。 ここでは、ファイルを開き、そこからデータを汲み取るための基本は FileInputStream である、として順番に見ていきましょう。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestApp {
public static void main(String[] args) {
try {
FileInputStream fileInputStream =
new FileInputStream("/Users/user1/hello.txt");
int i;
while ((i = fileInputStream.read()) != -1) {
if (0x1F < i && i < 0x7E) {
System.out.println((char) i);
}
}
fileInputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/Users/user1/hello.txt というパスにあるテキストファイルから、文字を読み込んで一文字ずつ表示しようとしています。
このテキストファイルには Hello! と書いてあります。
ファイルを開くなどの操作は不要です。FileInputStream のコンストラクタにファイルのパスを渡すだけで OK です。
この入力ストリームの read() メソッドは 1 バイト毎にデータを読み int 型の整数として返します。
では、テキストファイルから読み込んだデータを文字として標準出力に表示してみましょう。 入力元にはどんなデータが入っているか分からないものとして、念のため 0x1f から 0x7f までの範囲の値の場合のみ出力します。
結果は次のとおり。
確かに H e l l o ! という文字が表示されました。
Java の InputStreamReader でテキストファイルを読み込む
上でみたように、FileInputStream でも read() メソッドを使うことで、バイト列を読み込むことができます。 これを文字の列として読み込むための橋渡しをするのが、 InputStreamReader です。
名前が少々ややこしいのですが、前節で動作確認したのは (入力の)「ストリーム」(Stream) です。 今回出てきたのは (入力の)「ストリームリーダー」(StreamReader) です。
考え方としては「なんとかストリーム」というのがファイルとかバイト列そのものを指します。これに対しては通常 read() メソッドなどのデータへのアクセス用のメソッドがありますが、 通常原始的なものしかありません。
「なんとかリーダー」というものを使うことで、それらへの読み込み用の便利な機能を追加する感じです。
さて、InputStreamReader に戻ります。
InputStreamReader のコンストラクタには FileInputStream を渡します。
package com.keicode.java.test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class TestApp {
public static void main(String[] args) {
try {
int size;
char[] cbuf = new char[2];
InputStreamReader inReader =
new InputStreamReader(
new FileInputStream("/Users/user1/hello.txt"));
while ((size = inReader.read(cbuf)) != -1) {
System.out.print(cbuf);
System.out.println("(" + size + ")");
Arrays.fill(cbuf, '\0');
}
inReader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
こうして、もとの FileInputStream から文字ベースでデータを取り出す手段が手に入りました。
ちなみに、ここでは最大 2 文字ずつ数回に分けて読み出しているので、結果は次のようになります。
念のためいうと、小さいバッファでこうして繰り返し読むのは通常あまり望ましいことではないです。 基本的な考えは、下のレイヤーに現実的な大きめのサイズのバッファを渡してアプリケーション側での処理を少なくする方が良い場合が多いです。
Java の StringWriter による String のバッファリング
前の例ではチョット読んで、チョット書き出して、ということを繰り返しましたが、そうしないで読み込んだものを溜め込んで(バッファリング)しておいて、 全部読み込み終わってから出力してみましょう。
文字を溜め込むのは、StringWriter で実現できます。(この場合は StringBuilder や StringBuffer でも良いのですがここではあえて java.io.Writer の StringWriter を使っています)
package com.keicode.java.test;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
public class TestApp {
public static void main(String[] args) {
try {
int size;
char[] cbuf = new char[2];
InputStreamReader inReader =
new InputStreamReader(
new FileInputStream("/Users/user1/hello.txt"));
StringWriter sWriter = new StringWriter();
while ((size = inReader.read(cbuf)) != -1) {
sWriter.write(cbuf, 0, size);
}
System.out.println(sWriter.toString());
inReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
全部読み込んでから出力、ということで今度はちゃんと "Hello!" とつながって表示されました。
Java の FileReader
「ファイルを開いてそこから読み込む」という基本的な操作のために、FileReader というリーダーも用意されています。
こちらは上でやったみたいに FileInputStream を作ってそれを InputStreamReader に渡すということをやらなくとも、 FileReader にパスを渡すとその中でストリームをオープンして、読込みを可能な状態にしてくれます。
package com.keicode.java.test;
import java.io.FileReader;
import java.io.IOException;
public class TestApp {
public static void main(String[] args) {
try {
char[] cbuf = new char[1];
FileReader fileReader =
new FileReader("/Users/user1/hello.txt");
while ((fileReader.read(cbuf)) != -1) {
System.out.print("[");
System.out.print(cbuf);
System.out.println("]");
}
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ためしに 1 文字ずつ読み込むと次のようになりました。
Java の BufferedReader で一行毎に読込み
いよいよ次はテキストファイルを一行毎に読むという、よくやりそうなことをやります。
一行毎に読むということは、ある程度データを読んで溜め込んでおき、改行文字 (CR, LF) などを見つけて、そこまでを取り出す、という作業に他なりません。 つまり「一行ずつ読む」ということをするのは、バッファにデータをため込む必要があります。
その意味でリーダーは BufferedReader を使うのが自然と考えられ、 確かに BufferedReader クラスには readLine() メソッドが用意されており、改行文字までの一行を返します。
package com.keicode.java.test;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TestApp {
public static void main(String[] args) {
try {
BufferedReader buffReader =
new BufferedReader(
new FileReader("/Users/keisukeo/hello.txt"));
String s;
while ((s = buffReader.readLine()) != null) {
System.out.println(s);
}
buffReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
この実行結果は次のとおり。
これはとても簡単ですね。