Как да избегнем 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 е точно там, за да може приложението да я прочете.

Сега да кажем, че използваме приставката Maven JAR, за да пакетираме нашия код като 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.(FileInputStream.java:138) at java.io.FileInputStream.(FileInputStream.java:93) at java.io.FileReader.(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. Заключение

В тази бърза статия внедрихме файлове за зареждане като ресурси за classpath, за да позволим на нашия код да работи последователно, независимо от това как е опакован.

Както винаги, примерният код е достъпен в GitHub.