Java - Read file from classpath
Important TIPS when reading files on classpath
- You can read a resource using multiple approaches (not all work the same).
AClass.class.getClassLoader().getResourceAsStream(file); // preferred ClassLoader.getSystemResourceAsStream(resourcePath) AClass.class.getResourceAsStream()
- Depending on h~~~~ow the code is written you either NEED to use a
leading slash in the name of the resource loaded or don’t need to
use one.
- ClassLoader.getSystemResourceAsStream() expects an absolute path within the classpath, but does not allow a leading /. If you mistakenly use a leading /, it will fail to find the resource.
- In contrast, methods like Class.getResourceAsStream(“/path/to/resource”) do allow a leading /.
- So you have to know how the method you are calling is written, hopefully the JavaDocs make it clear!
- In modular environments (like Java modules) or containerized applications (like OSGi, Tomcat, Spring Boot), the system class loader may not have the same visibility as the context class loader or a class-specific class loader.
- In such environments, ClassLoader.getSystemResourceAsStream() might not be able to find resources that are loaded by other class loaders.
- If a file exists in multiple locations, the first one will be used. resolved from the top of the classpath (which typical).
- Resources can be relative to the class reading the resource or relative
to the top of the TREE/classpath. If a the CLASSPATH has multiple directories
or JAR files then EACH one of them is searched (in turn) in
the order listed in the Java
-cp
or-classpath
command line argument.
The recommendation for reading a resource is generally to prefer using AClass.class.getClassLoader().getResourceAsStream(file) over ClassLoader.getSystemResourceAsStream(resourcePath), especially in environments where class loader visibility can vary.
Sample Code
Given a source file and a settings file at
src/main/java/com/example/proj1/pkg1/Utils.java
src/main/resources/config/config.file
You can read the config.file file using:
Utils.readResource("/config/config.file");
Because of the way the code that loads the resource is written the file could also be read using.
Utils.readResource("config/config.file");
But as stated, it is recommended to use the leading slash to avoid confusion.
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
public class Utils {
/**
* Reads a file from the classpath and returns its content as a String.
*
* @param file The path to the file on the classpath.
* @return The content of the file as a String.
* @throws IllegalArgumentException If the file is not found on the classpath.
*/
public static String readResource(String file) {
// Try to load the file from the classpath
InputStream inputStream = Utils.class.getClassLoader().getResourceAsStream(file);
// If the file is not found, throw an exception
if (inputStream == null) {
throw new IllegalArgumentException("File not found on the classpath: " + file);
}
// Read the file content using BufferedReader
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
throw new RuntimeException("Error reading file: " + file, e);
}
}
}
Notes: Relative vs Absolute Classpath
When reading a resource the resource can be relative to the class that is reading the resource.
For example, a class
src/main/java/com/example/proj/pkg1/MyCode.java
src/main/java/com/example/proj/pkg1/mycode1.file
src/main/resources/config/config.file
src/main/resources/com/example/proj/pkg1/mycode2.file
And the resulting compiled code that gets put into a JAR file
or under target
when compiling with maven or a Java IDE.
target/classes/com/example/proj/pkg1/MyCode.java
target/classes/com/example/proj/pkg1/mycode2.file
target/classes/config/config.file
NOTE: mycode1.file
will not (by default) be copied to the target/classes
directory if you intended to have that file read as a resource then
you should move it to the src/main/resources
directory or make
update the pom.xml
file to include it (using instructions below)
To update the pom.xml file to copy
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.file</include>
</includes>
</resource>
</resources>
</build>