Come evitare l'eccezione Java FileNotFoundException durante il caricamento delle risorse

1. Panoramica

In questo tutorial, esploreremo un problema che può sorgere durante la lettura dei file di risorse in un'applicazione Java: in fase di esecuzione, la cartella delle risorse si trova raramente nella stessa posizione sul disco in cui si trova nel nostro codice sorgente.

Vediamo come Java ci consente di accedere ai file di risorse dopo che il nostro codice è stato impacchettato.

2. Lettura di file

Supponiamo che la nostra applicazione legga un file durante l'avvio:

try (FileReader fileReader = new FileReader("src/main/resources/input.txt"); BufferedReader reader = new BufferedReader(fileReader)) { String contents = reader.lines() .collect(Collectors.joining(System.lineSeparator())); }

Se eseguiamo il codice sopra in un IDE, il file viene caricato senza errori. Questo perché il nostro IDE utilizza la directory del nostro progetto come directory di lavoro corrente e la directory src / main / resources è lì per essere letta dall'applicazione.

Supponiamo ora di utilizzare il plugin Maven JAR per impacchettare il nostro codice come JAR.

Quando lo eseguiamo dalla riga di comando:

java -jar core-java-io2.jar

Vedremo il seguente errore:

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. Codice sorgente vs codice compilato

Quando creiamo un JAR, le risorse vengono inserite nella directory principale degli artefatti pacchettizzati.

Nel nostro esempio, vediamo che la configurazione del codice sorgente ha input.txt in src / main / resources nella nostra directory del codice sorgente.

Nella struttura JAR corrispondente, tuttavia, vediamo:

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

Qui, input.txt si trova nella directory principale del JAR. Quindi, quando il codice viene eseguito, vedremo FileNotFoundException .

Anche se abbiamo modificato il percorso in /input.txt, il codice originale non potrebbe caricare questo file poiché le risorse non sono solitamente indirizzabili come file su disco. I file di risorse sono impacchettati all'interno del JAR e quindi abbiamo bisogno di un modo diverso per accedervi.

4. Risorse

Usiamo invece il caricamento delle risorse per caricare le risorse dal classpath invece di un percorso di file specifico. Funzionerà indipendentemente da come il codice è confezionato:

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 () esamina il classpath per la risorsa data. La barra iniziale sull'input di getResourceAsStream () indica al caricatore di leggere dalla base del classpath. Il contenuto del nostro file JAR si trova sul classpath , quindi questo metodo funziona.

Un IDE tipicamente include src / main / resources nel suo classpath e, quindi, trova i file.

5. conclusione

In questo rapido articolo, abbiamo implementato il caricamento dei file come risorse del percorso di classe, per consentire al nostro codice di funzionare in modo coerente indipendentemente da come è stato confezionato.

Come sempre, il codice di esempio è disponibile su GitHub.