Home > Blockchain >  How to build a Jar file that include external files
How to build a Jar file that include external files

Time:11-18

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:

enter image description here

I can run the code successfully. The way I generated Jar is as follows:

enter image description here

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, not getClass(). 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 (vs File 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.
  • Related