10
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Javaのバージョン別、テキストファイルを一括で読み込む方法まとめ

Last updated at Posted at 2021-05-03

(この記事は 地平線に行く とのマルチポストです)

前回の記事(Javaのバージョン別、1行ずつファイルを読む方法まとめ - Qiita)への感想で、このような話がありました。

というわけで、今回はテキストファイルを一括で読み込む方法をまとめました。
(前回と被っている点は省略しているので、まだ読んでない人は先に前回の記事をどうぞ)

Java 1.1, 1.2, 1.3

private static String readString(File file) throws IOException {
    Reader reader = null;
    try {
        reader = new InputStreamReader(new FileInputStream(file), "UTF-8");

        StringBuffer sb = new StringBuffer();
        int len;
        char[] buffer = new char[1024 * 8];
        while ((len = reader.read(buffer)) != -1) {
            sb.append(buffer, 0, len);
        }
        return sb.toString();
    } finally {
        if (reader != null) {
            reader.close();
        }
    }
}

まだこのころはめんどくさいです。

FileInputStream でファイルを読み込み、InputStreamReader で指定した文字コードにデコードするようにしています。
読み込む際は、char[] でバッファして StringBuffer に追加していっています。

ちなみに、char[] でバッファしながら読み込んでいるので、 BufferedReader でラップする必要はありません。

Java 1.4, 1.5, 6

private static String readString(File file) throws IOException {
    CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();

    try (FileInputStream stream = new FileInputStream(file)) {
        FileChannel channel = stream.getChannel();
        ByteBuffer bb = channel.map(MapMode.READ_ONLY, 0, channel.size());

        CharBuffer cb = decoder.decode(bb);

        return cb.toString();
    }
}

ファイルチャネルが使えるようになりました。

このバージョンで追加された Charset クラスから、CharsetDecoder というデコーダを取得できます。
これに FileChannel#map​(FileChannel.MapMode mode, long position, long size) で取得した MappedByteBuffer を渡すことで、ファイルを読み込めます。

MappedByteBuffer はファイルの内容をメモリにマッピングして扱う(メモリマップドファイル)ので、大きなファイルの時に効率的に処理が行われます。
逆に言うと、小さいファイルを読み込む場合は性能が悪いです。
その場合は、今まで通り InputStream で読み込みましょう。

ほとんどのオペレーティング・システムでは、ファイルをメモリーにマッピングするほうが、通常のreadメソッドまたはwriteメソッドを使って数十キロバイトのデータの読み込みまたは書込みを行うよりも負荷が大きくなります。 性能を重視するなら、比較的大きめのファイルだけをマッピングすることをお薦めします。
FileChannel (Java SE 15 & JDK 15)

----
この FileChannelmap メソッドを使うやり方はひしだまさんの記事を読んで知りました!
Javaバッファークラスメモ(Hishidama's Java Buffer Memo)

Java 7, 8, 9, 10

private static String readString(Path path) throws IOException {
    byte[] bytes = Files.readAllBytes(path);
    
    return new String(bytes, StandardCharsets.UTF_8);
}

Files クラスが追加され、これに一括でファイルを byte[] として読み込むメソッドが用意されました。
これを使ってファイルを読み込めば、あとは String クラスを new するだけです。

ちなみに、このバージョンでファイルからすべての行を読み取る Files#readAllLines​(Path, Charset) も追加されました。
この戻り値は List<String> です。行ごとに処理をしたい場合はこちらが便利です。

Java 11~

private static String readString(Path path) throws IOException {
    return Files.readString(path, StandardCharsets.UTF_8);
}

ひとつのメソッドでファイルをすべて読み込めるようになりました。 1

このメソッドの実装では StringCoding というインターナルなクラスを使っているので、new String(bytes, StandardCharsets.UTF_8) とするよりも効率的な処理になっています。

まとめ

めんどくさかった処理も、Java のバージョンが上がるごとに簡単に書けるようになっています。
なので、積極的に新しい Java を使っていきましょう!

関連記事

  1. Google で検索して一番上に出てくる JavaDoc が Java 8 なせいで、この Java 11 で追加されたメソッドを忘れられがちです…。

10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?