Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
10
Help us understand the problem. What is going on with this article?
@YujiSoftware

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

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

前回の記事(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
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
10
Help us understand the problem. What is going on with this article?