Hoe u de Java FileNotFoundException kunt vermijden bij het laden van bronnen

1. Overzicht

In deze zelfstudie onderzoeken we een probleem dat kan optreden bij het lezen van bronbestanden in een Java-toepassing: tijdens runtime bevindt de bronmap zich zelden op dezelfde locatie op de schijf als in onze broncode.

Laten we eens kijken hoe we met Java toegang hebben tot bronbestanden nadat onze code is verpakt.

2. Bestanden lezen

Laten we zeggen dat onze applicatie een bestand leest tijdens het opstarten:

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

Als we de bovenstaande code in een IDE uitvoeren, wordt het bestand zonder fouten geladen. Dit is zo omdat onze IDE gebruikt onze projectdirectory als de huidige werkdirectory en de src / main / resources map is daar voor de toepassing om te lezen.

Laten we nu zeggen dat we de Maven JAR-plug-in gebruiken om onze code als een JAR te verpakken.

Wanneer we het op de opdrachtregel uitvoeren:

java -jar core-java-io2.jar

We zien de volgende foutmelding:

Uitzondering in thread "main" java.io.FileNotFoundException: src / main / resources / input.txt (bestand of map bestaat niet) op java.io.FileInputStream.open0 (Native Method) op java.io.FileInputStream.open (FileInputStream .java: 195) op java.io.FileInputStream. (FileInputStream.java:138) op java.io.FileInputStream. (FileInputStream.java:93) op java.io.FileReader. (FileReader.java:58) op com. baeldung.resource.MyResourceLoader.loadResourceWithReader (MyResourceLoader.java:14) op com.baeldung.resource.MyResourceLoader.main (MyResourceLoader.java:37)

3. Broncode versus gecompileerde code

Wanneer we een JAR bouwen, worden de bronnen in de hoofdmap van de verpakte artefacten geplaatst.

In ons voorbeeld zien we dat de installatie van de broncode input.txt in src / main / resources in onze broncodemap.

In de overeenkomstige JAR-structuur zien we echter:

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

Hier, input.txt bevindt zich in de hoofdmap van de JAR. Dus wanneer de code wordt uitgevoerd, zien we het FileNotFoundException.

Zelfs als we het pad naar /input.txt de originele code kon dit bestand niet laden als bronnen zijn gewoonlijk niet adresseerbaar als bestanden op schijf. De bronbestanden zijn verpakt in de JAR en daarom hebben we een andere manier nodig om ze te openen.

4. Middelen

Laten we in plaats daarvan het laden van bronnen gebruiken naar laad bronnen van het klassenpad in plaats van een specifieke bestandslocatie. Dit werkt ongeacht hoe de code is verpakt:

probeer (InputStream inputStream = getClass (). getResourceAsStream ("/ input.txt"); BufferedReader reader = nieuwe BufferedReader (nieuwe InputStreamReader (inputStream))) {String content = reader.lines () .collect (Collectors.joining (System. lineSeparator ())); }

ClassLoader.getResourceAsStream () kijkt naar het klassenpad voor de opgegeven bron. De leidende schuine streep op de invoer naar getResourceAsStream () vertelt de lader om te lezen vanaf de basis van het klassenpad. De inhoud van ons JAR-bestand staat op het klassenpad, dus deze methode werkt.

Een IDE omvat doorgaans src / main / resources op zijn klassenpad en vindt dus de bestanden.

5. Conclusie

In dit korte artikel hebben we het laden van bestanden geïmplementeerd als klassenpadbronnen, zodat onze code consistent kan werken, ongeacht hoe deze is verpakt.

Zoals altijd is de voorbeeldcode beschikbaar op GitHub.