Reading a resource file from within jar
Categories:
Reading Resource Files from Within a Java JAR

Learn how to reliably access and load resource files (like configuration, images, or text files) that are embedded directly within your Java application's JAR file, covering common pitfalls and best practices.
When developing Java applications, it's common to bundle various non-code assets—such as configuration files, images, sound files, or localized text—directly into the application's JAR (Java Archive) file. These assets are known as 'resources'. Accessing these resources correctly from within the running application can sometimes be tricky, especially when dealing with different deployment environments or classloaders. This article will guide you through the most robust methods for reading resource files embedded within your JAR.
Understanding Java Resources and ClassLoaders
In Java, resources are typically loaded via a ClassLoader
. A ClassLoader
is responsible for loading classes and resources into the Java Virtual Machine (JVM). When your application runs from a JAR, the resources are not treated as regular files on the file system. Instead, they are entries within the JAR archive itself. Attempting to access them using java.io.File
with a direct path will almost always fail because the File
API expects a file system path, not an entry within an archive.
flowchart TD A[Application Code] --> B{ClassLoader.getResourceAsStream()} B --> C{JAR File} C --> D[Embedded Resource] D --> E[InputStream] E --> F[Read Resource Content] B -- X Failed --> G[File API (Incorrect)] G --> H[FileNotFoundException]
Flow for correctly loading resources versus incorrect file system access.
The ClassLoader.getResourceAsStream()
Method
The most reliable and recommended way to read a resource embedded in a JAR is by using ClassLoader.getResourceAsStream(String name)
. This method returns an InputStream
for reading the resource, or null
if the resource could not be found. The name
parameter should be the path to the resource relative to the root of the classpath. For example, if your resource config.properties
is located in the src/main/resources
directory of a Maven project, its path would simply be config.properties
.
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class ResourceLoader {
public static void main(String[] args) {
String resourceName = "my_resource.txt"; // Assumes my_resource.txt is in src/main/resources
readResource(resourceName);
String nestedResourceName = "config/app.properties"; // Assumes config/app.properties
readResource(nestedResourceName);
}
public static void readResource(String resourcePath) {
// Get the ClassLoader for the current class
ClassLoader classLoader = ResourceLoader.class.getClassLoader();
// Use getResourceAsStream to get an InputStream to the resource
try (InputStream inputStream = classLoader.getResourceAsStream(resourcePath)) {
if (inputStream == null) {
System.err.println("Resource not found: " + resourcePath);
return;
}
// Read the content of the resource
try (InputStreamReader streamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(streamReader)) {
System.out.println("--- Content of " + resourcePath + " ---");
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
System.out.println("-----------------------------------");
} catch (IOException e) {
System.err.println("Error reading resource: " + resourcePath + ", " + e.getMessage());
}
} catch (IOException e) {
System.err.println("Error closing input stream for resource: " + resourcePath + ", " + e.getMessage());
}
}
}
Example of reading a text resource using ClassLoader.getResourceAsStream()
.
com/example/data/file.json
), you should use that full path, including the package separators as slashes, not dots.Alternative: Class.getResourceAsStream()
Another common approach is to use Class.getResourceAsStream(String name)
. This method behaves slightly differently depending on whether the resource name starts with a /
(slash) or not:
- If
name
starts with/
: The leading slash is dropped, and the name is passed to the class'sClassLoader.getResourceAsStream()
method. This means the path is absolute to the classpath root. - If
name
does NOT start with/
: The path is considered relative to the package of the class whosegetResourceAsStream()
method is being called. For example, ifMyClass.class.getResourceAsStream("data.txt")
is called, andMyClass
is incom.example
, it will look forcom/example/data.txt
.
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
package com.example.app;
public class MyClass {
public static void main(String[] args) {
// Resource in the same package as MyClass (com/example/app/local_resource.txt)
readResourceRelative("local_resource.txt");
// Resource at the classpath root (my_resource.txt)
readResourceAbsolute("/my_resource.txt");
// Resource in a specific package (com/example/config/app.properties)
readResourceAbsolute("/com/example/config/app.properties");
}
public static void readResourceRelative(String resourcePath) {
try (InputStream inputStream = MyClass.class.getResourceAsStream(resourcePath)) {
if (inputStream == null) {
System.err.println("Relative resource not found: " + resourcePath);
return;
}
// ... (read content as before) ...
System.out.println("--- Content of relative resource " + resourcePath + " ---");
try (InputStreamReader streamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(streamReader)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
System.out.println("-----------------------------------");
} catch (IOException e) {
System.err.println("Error reading relative resource: " + resourcePath + ", " + e.getMessage());
}
}
public static void readResourceAbsolute(String resourcePath) {
try (InputStream inputStream = MyClass.class.getResourceAsStream(resourcePath)) {
if (inputStream == null) {
System.err.println("Absolute resource not found: " + resourcePath);
return;
}
// ... (read content as before) ...
System.out.println("--- Content of absolute resource " + resourcePath + " ---");
try (InputStreamReader streamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(streamReader)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
System.out.println("-----------------------------------");
} catch (IOException e) {
System.err.println("Error reading absolute resource: " + resourcePath + ", " + e.getMessage());
}
}
}
Example using Class.getResourceAsStream()
with both relative and absolute paths.
Class.getResourceAsStream()
with relative paths, as the behavior depends on the package of the calling class. For consistency and clarity, using ClassLoader.getResourceAsStream()
with absolute paths (relative to the classpath root) is often preferred.Handling Different Resource Types
While the examples above focus on text files, the InputStream
returned by getResourceAsStream()
can be used to read any type of resource: images, audio, binary data, etc. You simply need to use the appropriate Java I/O classes to process the InputStream
.
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
public class ImageLoader {
public static void main(String[] args) {
String imageResource = "images/logo.png"; // Assumes images/logo.png in src/main/resources
try {
BufferedImage image = loadImageResource(imageResource);
if (image != null) {
System.out.println("Successfully loaded image: " + imageResource);
System.out.println("Image dimensions: " + image.getWidth() + "x" + image.getHeight());
// Further processing of the image...
} else {
System.err.println("Failed to load image: " + imageResource);
}
} catch (IOException e) {
System.err.println("Error loading image: " + e.getMessage());
}
}
public static BufferedImage loadImageResource(String resourcePath) throws IOException {
ClassLoader classLoader = ImageLoader.class.getClassLoader();
try (InputStream inputStream = classLoader.getResourceAsStream(resourcePath)) {
if (inputStream == null) {
System.err.println("Image resource not found: " + resourcePath);
return null;
}
return ImageIO.read(inputStream);
}
}
}
Loading an image resource from a JAR using ImageIO.read()
.
Best Practices and Common Pitfalls
To ensure robust resource loading, consider these points:
- Always use
getResourceAsStream()
: Avoidnew File("path/to/resource")
for embedded resources. - Close InputStreams: Always close the
InputStream
after use to prevent resource leaks. The try-with-resources statement is ideal for this. - Handle
null
returns: Check ifgetResourceAsStream()
returnsnull
before attempting to use theInputStream
. - Path Consistency: Use forward slashes (
/
) for path separators, even on Windows, as JARs use this convention. - Maven/Gradle Projects: Place resources in
src/main/resources
(orsrc/test/resources
for tests). These directories are automatically added to the classpath by build tools. - Context ClassLoader: In complex environments (e.g., web servers, OSGi), the
Thread.currentThread().getContextClassLoader()
might be necessary to get the correctClassLoader
.
ResourceUtils
or ClassPathResource
for a more abstracted way of accessing resources, which handles both file system and classpath resources seamlessly.