📁

Javaのファイル入出力は、FileではなくPathを使う

に公開

環境

JDK 25(Java 7以降であればOKのはずです。たぶん。)

前提知識

https://zenn.dev/masatoshi_tada/articles/05c4450c599321

FileとPathの関係

Fileクラス は、Java 1.0のころから存在するファイルおよびディレクトリを表すクラスです。

対して Pathインタフェース は、ファイルおよびディレクトリなどのパス(相対パスでも絶対パスでもOK)を表す、Java 7から導入された新しいインタフェースです。Pathインタフェースの実装クラスはmacOS・WindowsなどOSごとに存在します。そして、これらの実装クラスを我々が意識することは有りません。

Fileクラスは現代でも非推奨になっていたりはしません。しかし、

  • Pathインタフェースの方が全体的にスッキリ書ける
  • Fileクラスではできないことが一部ある

ので、現代では基本的にはPathインタフェースを使いましょう。

PathインタフェースなどのAPIを総称して NIO.2 と呼んだりします。

PathインタフェースのJavadocはこちら。どんなメソッドがあるのか眺めてみてください。

https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/file/Path.html

FileとPathの相互変換

FileクラスにはtoPath()メソッド、PathインタフェースにはtoFile()メソッドが定義されているので、相互に変換可能です。

// File -> Path
File file1 = new File("...");
Path path1 = file1.toPath();

// Path -> File
Path path2 = Path.of("...");
File file2 = path2.toFile();

古くから存在する業務コードやライブラリなどでFileクラスが使われている際に、これらのメソッドを使ったりします。

テキストファイル読み込みの比較

まずはNIO.2の例です。

NIO.2で読み込み
Path targetFile = Path.of("/tmp/test/sample.txt");
try (Stream<String> stream = Files.lines(targetFile, StandardCharsets.UTF_8)) {
    // 各行を[]で囲って、標準出力に出力
    List<String> list = stream.map(line -> "[" + line + "]")
            .toList();
    for (String line : list) {
        // 読み込んだ行に対して何らかの処理を行う
        // 今回はサンプルなので表示するだけ
        System.out.println(line);
    }
} catch (IOException e) {
    // 業務コードでe.printStackTrace()を使うことはめったにありません。
    // 業務では各プロジェクトのルールに合わせて、例外の再スローやログの出力などを行ってください。
    e.printStackTrace();
}

NIO.2では、ファイル等を処理するメソッドはほぼすべて Filesクラス にstaticメソッドとして定義されています。

どんなメソッドがあるか、Javadocをザッと眺めて確認してみてください。

https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/file/Files.html

次にFileクラスの例です。

Fileで読み込み
File targetFile = new File("/tmp/test/sample.txt");
try (FileInputStream fis = new FileInputStream(targetFile);
        InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
        BufferedReader br = new BufferedReader(isr)) {
    for (String line; (line = br.readLine()) != null; ) {
        System.out.println("[" + line + "]");
    }
} catch (IOException e) {
    e.printStackTrace();
}

FileInputStreamInputStreamReaderBufferedReaderと3つも作る必要があったり、for文で(line = br.readLine()) != null;があったりと、けっこうややこしい感じですね。

まとめ

繰り返しになりますが、基本的にはNIO.2を使いましょう。

Web上のブログ記事や生成AIの出力にFileクラスを使った例があったら、NIO.2で書き換えられないか考えてみてください。その際は、PathFilesのJavadocを読むとヒントが得られますよ。

Discussion