I want to include the text file in resources folder to the Jar file. Here is the minimal example:
import java.io.File;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Main main = new Main();
main.readFile( "test.txt" );
}
public void readFile(String fileName){
File file = new File( getClass().getResource( fileName ).getPath() );
try{
Scanner scanner = new Scanner( file );
while ( scanner.hasNextLine() ){
System.out.println( scanner.nextLine() );
}
}catch (Exception e){
System.out.println( e );
}
}
}
Here is what's in the test.txt file:
hello
world
This is how my project looks like:
I can run the code successfully. The way I generated Jar is as follows:
I have already added resources folder by clicking " " symbol. However, when I call the generated Jar file, it is still complaining FileNotFoundException.
Any suggestions?
CodePudding user response:
new File
represents a File. As in, a file. An entry in a jar file isn't a File.
Your code cannot work for what you want to do.
File is the wrong abstraction. You want InputStream
or possibly URL, both of which can represent files, network streams, on-the-fly generated stuff, and, yes, entries in jar files.
public void readFile(String fileName) {
try (var in = ThisClass.class.getResourceAsStream(fileName)) {
Scanner scanner = new Scanner(in, StandardCharsets.UTF_8);
// proceed here.
} catch (IOException e) {
throw new RuntimeException("Uncaught", e);
}
}
A few things are going on in that snippet:
- Use
ThisClass.class
, notgetClass()
. The getClass route breaks when you subclass. You might not do so here, but you might later; it's better to write code that always works when it's just as short. - It's a resource, you must close it. This code therefore uses try-with-resources.
- We get an InputStream (
getResourceAsStream
returns an inputstream), which is the right level of abstraction that can represent an entry inside a jar (vsFile
which just can't do that). - We tell the scanner what the charset encoding is. Otherwise you get platform default, which is wrong and nasty: On your own computer it'll always work, then you run it on another system and it fails. Always, always specify charset encoding anytime bytes are turned into chars (or vice versa).
e.printStackTrace()
is evil. Don't ever handle exceptions that way. If you have no idea (and that's fair here; if this throws IOEx, clearly something is badly wrong and it's a good idea for your app to just crash with as much detail as is possible) - the above is the right way to deal with it.