Skip to content

Instantly share code, notes, and snippets.

@gkhays
Last active October 16, 2023 12:55
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gkhays/1d90f75d9347cc2d7bc70f7bd56f31e7 to your computer and use it in GitHub Desktop.
Save gkhays/1d90f75d9347cc2d7bc70f7bd56f31e7 to your computer and use it in GitHub Desktop.
How to load resources and files in Java

Resources and the Class Path

See also: Read a File from Disk into a String.

The problem started when I attempted to pass what I thought was a valid relative path to a J2EE test method. I mistakenly thought the unqualified file name or the unqualified file name with a leading slash would suffice. It did not. The solution ended up being the file name prefixed with the resource path, in this case:

target/test-classes/test.txt

A quick way to figure out the resource path.

System.out.printf("Resource Path: %s\n", ListResources.class
				.getResource("").getPath());

Output: Resource Path: /C:/Users/gkh/gist/bin/org/gkh/

Next, get the path of the currently running Java program.

ClassLoader loader = ListResources.class.getClassLoader();
System.out.printf("Resource: %s\n", loader.getResource("org/gkh/ListResources.class"));

Resource: file:/C:/Users/haysg/Development/WorkBench/Snippets/Snippets/bin/org/gkh/ListResources.class

Whereas the system property java.class.path shows what would be passed with the -cp or -classpath switch.

System.out.printf("Class Path: %s\n", System.getProperty("java.class.path"));

Output:

Class Path: C:\Users\gkh\gist\bin;C:\Users\gkh\lib\jackson-core-2.4.4.jar;C:\Users\gkh\gist\lib\jaxen-1.1.6.jar;...

A resource is a URL. Note: In JAVA EE, you would use a leading slash, e.g. "/a.txt".

URL url = ListResources.class.getResource("a.txt");
System.out.println(url.getFile());

Output: Resource URL: /C:/Users/gkh/gist/bin/org/gkh/a.txt

Using the Context Class Loader

Enumeration<URL> resources = Thread.currentThread()
		.getContextClassLoader().getResources("org/gkh");
while (resources.hasMoreElements()) {
	URL url1 = resources.nextElement();
	System.out.printf("Resource URL: %s\n", url1);
	Scanner scanner = new Scanner((InputStream)url1.getContent());
	String s = scanner.useDelimiter("\\A").next();
	System.out.printf("Resource Content: %s\n", s);
	scanner.close();
}

Output:

Resource URL: file:/C:/Users/haysg/Development/WorkBench/Snippets/Snippets/bin/org/gkh
Resource Content: a.txt
ListResources.class
ListThreads.class
ListThreads$1.class
Log4jExample.class

FileInputStream with Relative Path

It is possible to create a FileInputStream using a relative path, the key is to remember that not only must you specify the root of the class path but also the package scope. A helpful article in this regard is FileInputStream doesn't work with the relative path. In particular, see the responses from Michael and BackSlash.

private String inputStreamToString(InputStream in) {
	Scanner scanner = new Scanner(in);
	String contents = scanner.useDelimiter("\\A").next();
	scanner.close();
	return contents;
}
	
InputStream is = new FileInputStream("bin/org/gkh/a.txt");
String contents = inputStreamToString(is);

Odds and Ends

You cannot directly load a URL with a path name, with or without a leading slash. In this case, the code will throw a FileNotFoundException.

URL fileURL = new URL("file:/" + resourceName);
fileURL.getContent();

Whereas URL fileURL = new URL(resoureName) will throw a MalformedURLException.

When loaded with class.getResource, the contents of the resource are created as a plain text input stream.

URL url2 = ListResources.class.getResource(resourceName);
System.out.println(url.getContent());

Output: sun.net.www.content.text.PlainTextInputStream@2f92e0f4

package org.gkh;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.Scanner;
public class ListResources {
public static String inputStreamToString(InputStream in) {
Scanner scanner = new Scanner(in);
String contents = scanner.useDelimiter("\\A").next();
scanner.close();
return contents;
}
public static void main(String[] args) throws IOException {
System.out.printf("Resource Path: %s\n", ListResources.class
.getResource("").getPath());
ClassLoader loader = ListResources.class.getClassLoader();
System.out.printf("Resource: %s\n",
loader.getResource("org/gkh/ListResources.class"));
System.out.printf("Class Path: %s\n",
System.getProperty("java.class.path"));
// Note: In JAVA EE, you would use a leading slash.
URL url = ListResources.class.getResource("a.txt");
System.out.printf("Resource URL: %s\n", url.getFile());
System.out.println("Using the Context Class Loader");
Enumeration<URL> resources = Thread.currentThread()
.getContextClassLoader().getResources("org/gkh");
while (resources.hasMoreElements()) {
URL url1 = resources.nextElement();
System.out.printf("Resource URL: %s\n", url1);
Scanner scanner = new Scanner((InputStream)url1.getContent());
String s = scanner.useDelimiter("\\A").next();
System.out.printf("Resource Content: %s\n", s);
scanner.close();
}
String resourceName = "a.txt";
URL url2 = ListResources.class.getResource(resourceName);
InputStream in = ListResources.class.getResourceAsStream(resourceName);
// sun.net.www.content.text.PlainTextInputStream@2f92e0f4
System.out.println(url.getContent());
String contents = inputStreamToString(in);
System.out.printf("The contents of [%s]: %s\n", resourceName, contents);
InputStream is = new FileInputStream("bin/org/gkh/a.txt");
contents = inputStreamToString(is);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment