リソースをロードするときにJava FileNotFoundExceptionを回避する方法

1. 概要

このチュートリアルでは、Javaアプリケーションでリソースファイルを読み取るときに発生する可能性のある問題について説明します。実行時に、リソースフォルダーがソースコードと同じディスク上の同じ場所にあることはほとんどありません。
*コードをパッケージ化した後、Javaを使用してリソースファイルにアクセスする方法を見てみましょう。*

2. ファイルを読む

アプリケーションが起動時にファイルを読み取るとしましょう:
try (FileReader fileReader = new FileReader("src/main/resources/input.txt");
     BufferedReader reader = new BufferedReader(fileReader)) {
    String contents = reader.lines()
      .collect(Collectors.joining(System.lineSeparator()));
}
IDEで上記のコードを実行すると、エラーなしでファイルがロードされます。 これは、* IDEがプロジェクトディレクトリを現在の作業ディレクトリ*として使用し、_src / main / resources_ディレクトリがアプリケーションが読み取るためにそこにあるためです。
では、https://www.baeldung.com/executable-jar-with-maven [Maven JAR plugin]を使用してコードをJARとしてパッケージ化するとしましょう。
コマンドラインで実行すると:
java -jar core-java-io2.jar
次のエラーが表示されます。
Exception in thread "main" java.io.FileNotFoundException:
    src/main/resources/input.txt (No such file or directory)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:195)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)
    at java.io.FileInputStream.<init>(FileInputStream.java:93)
    at java.io.FileReader.<init>(FileReader.java:58)
    at com.baeldung.resource.MyResourceLoader.loadResourceWithReader(MyResourceLoader.java:14)
    at com.baeldung.resource.MyResourceLoader.main(MyResourceLoader.java:37)

3. ソースコードとコンパイル済みコード

JARをビルドすると、リソースはパッケージ化されたアーティファクトのルートディレクトリに配置されます。
この例では、ソースコードのセットアップの_input.txt_が、ソースコードディレクトリの_src / main / resources_にあることがわかります。
ただし、対応するJAR構造には次のように表示されます。
META-INF/MANIFEST.MF
META-INF/
com/
com/baeldung/
com/baeldung/resource/
META-INF/maven/
META-INF/maven/com.baeldung/
META-INF/maven/com.baeldung/core-java-io-files/
input.txt
com/baeldung/resource/MyResourceLoader.class
META-INF/maven/com.baeldung/core-java-io-files/pom.xml
META-INF/maven/com.baeldung/core-java-io-files/pom.properties
ここで、_input.txt_はJARのルートディレクトリにあります。 したがって、コードを実行すると、_FileNotFoundException_が表示されます。
パスを_ / input.txt_に変更した場合でも、リソースは通常ディスク上のファイルとしてアドレス指定できないため、元のコードはこのファイルをロードできませんでした。 **リソースファイルはJAR内にパッケージ化されているため、それらにアクセスする別の方法が必要です。

4. リソース

代わりに、リソースのロードを使用して、特定のファイルの場所ではなく、クラスパスからリソースをロードしましょう*。 これは、コードのパッケージ方法に関係なく機能します。
try (InputStream inputStream = getClass().getResourceAsStream("/input.txt");
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
    String contents = reader.lines()
      .collect(Collectors.joining(System.lineSeparator()));
}
_ClassLoader.getResourceAsStream()_は、指定されたリソースのクラスパスを調べます。 _getResourceAsStream()_への入力の先頭のスラッシュは、ローダーにクラスパスのベースから読み取るように指示します。 * JARファイルの内容はクラスパスにあるため、このメソッドは機能します。
  • IDEは通常、クラスパスに_src / main / resources_を含むため、ファイルを検索します。

5. 結論

この簡単な記事では、ファイルのロード方法に関係なくコードを一貫して機能させるために、ファイルをクラスパスリソースとしてロードする方法を実装しました。
いつものように、サンプルコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-io-files[GitHub上]で入手できます。