Load a Resource Contained in a Jar

Reading a resource file from within jar

Rather than trying to address the resource as a File just ask the ClassLoader to return an InputStream for the resource instead via getResourceAsStream:

try (InputStream in = getClass().getResourceAsStream("/file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
// Use resource
}

As long as the file.txt resource is available on the classpath then this approach will work the same way regardless of whether the file.txt resource is in a classes/ directory or inside a jar.

The URI is not hierarchical occurs because the URI for a resource within a jar file is going to look something like this: file:/example.jar!/file.txt. You cannot read the entries within a jar (a zip file) like it was a plain old File.

This is explained well by the answers to:

  • How do I read a resource file from a Java jar file?
  • Java Jar file: use resource errors: URI is not hierarchical

Load a resource contained in a jar

It sounds like you're then trying to load the resource using a FileInputStream or something like that. Don't do that: instead of calling getResource, call getResourceAsStream and read the data from that.

(You could load the resources from the URL instead, but calling getResourceAsStream is a bit more convenient.)

EDIT: Having seen your updated answer, it seems other bits of code rely on the data being in a physical single file in the file system. The answer is therefore not to bundle it in a jar file in the first place. You could check whether it's in a separate file, and if not extract it to a temporary file, but that's pretty hacky IMO.

Loading resource files within a jar

This snippet of code worked for me:

Clip clip = null;
ClassLoader cl = this.getClass().getClassLoader();
AudioInputStream ais;
URL url = cl.getResource("com/example/project/assets/TestSound.wav");
System.out.println(url);
try {
ais = AudioSystem.getAudioInputStream(url);
clip = AudioSystem.getClip();
clip.open(ais);
}
catch (Exception e) {
e.printStackTrace();
System.exit(1);
}

The important thing is not adding the /src/ folder to the class path.

The critical change is changing cl.getResource("/com/example/project/assets/TestSound.wav") to cl.getResource("com/example/project/assets/TestSound.wav");
because /com/... indicates that the path is absolute, whereas com/... indicates that the path is relative.

For example,

System.out.println(new File("/Test.File").getAbsolutePath());
System.out.println(new File("Test.File").getAbsolutePath());

return

/Test.File
/Users/alphadelta/Documents/Workspace/TestProject/Test.File

respectively.

The first File created is created using "/Test.File", which is absolute. The second is created using "Test.File", which is relative to the project root in eclipse.

How to access resources in JAR file?

To load an image from a JAR resource use the following code:

Toolkit tk = Toolkit.getDefaultToolkit();
URL url = getClass().getResource("path/to/img.png");
Image img = tk.createImage(url);
tk.prepareImage(img, -1, -1, null);

How to load a resource in both IDE and .jar using the same String

If you load a resource in Java you alway can use '/' as separator.

Try

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url = classLoader.getResource("res/shader/some_shader.glsl"); // no leading slash

Make shure your JAR with the resource is in your JVM Classpath (-cp or -classpath).

Edit:
You must use url.openStream() to get an InputStream - not new File(). Your resource is not a file, becaus it is inside the JAR

Load resource from class's own JAR file

Alternatively you could use the JarURLConnection if you know the exact jar in which your file resides:

jar:<url>!/{entry}


Related Topics



Leave a reply



Submit