How to get a path to a resource in a Java JAR file

JavaResourcesPath

Java Problem Overview


I am trying to get a path to a Resource but I have had no luck.

This works (both in IDE and with the JAR) but this way I can't get a path to a file, only the file contents:

ClassLoader classLoader = getClass().getClassLoader();
PrintInputStream(classLoader.getResourceAsStream("config/netclient.p"));

If I do this:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("config/netclient.p").getFile());

The result is: java.io.FileNotFoundException: file:/path/to/jarfile/bot.jar!/config/netclient.p (No such file or directory)

Is there a way to get a path to a resource file?

Java Solutions


Solution 1 - Java

This is deliberate. The contents of the "file" may not be available as a file. Remember you are dealing with classes and resources that may be part of a JAR file or other kind of resource. The classloader does not have to provide a file handle to the resource, for example the jar file may not have been expanded into individual files in the file system.

Anything you can do by getting a java.io.File could be done by copying the stream out into a temporary file and doing the same, if a java.io.File is absolutely necessary.

Solution 2 - Java

When loading a resource make sure you notice the difference between:

getClass().getClassLoader().getResource("com/myorg/foo.jpg") //relative path

and

getClass().getResource("/com/myorg/foo.jpg")); //note the slash at the beginning

I guess, this confusion is causing most of problems when loading a resource.


Also, when you're loading an image it's easier to use getResourceAsStream():

BufferedImage image = ImageIO.read(getClass().getResourceAsStream("/com/myorg/foo.jpg"));

When you really have to load a (non-image) file from a JAR archive, you might try this:

File file = null;
String resource = "/com/myorg/foo.xml";
URL res = getClass().getResource(resource);
if (res.getProtocol().equals("jar")) {
	try {
		InputStream input = getClass().getResourceAsStream(resource);
		file = File.createTempFile("tempfile", ".tmp");
		OutputStream out = new FileOutputStream(file);
		int read;
		byte[] bytes = new byte[1024];

		while ((read = input.read(bytes)) != -1) {
			out.write(bytes, 0, read);
		}
		out.close();
		file.deleteOnExit();
	} catch (IOException ex) {
		Exceptions.printStackTrace(ex);
	}
} else {
	//this will probably work in your IDE, but not from a JAR
	file = new File(res.getFile());
}

if (file != null && !file.exists()) {
	throw new RuntimeException("Error: File " + file + " not found!");
}

Solution 3 - Java

The one line answer is -

String path = this.getClass().getClassLoader().getResource(<resourceFileName>).toExternalForm()

Basically getResource method gives the URL. From this URL you can extract the path by calling toExternalForm().

Solution 4 - Java

I spent a while messing around with this problem, because no solution I found actually worked, strangely enough! The working directory is frequently not the directory of the JAR, especially if a JAR (or any program, for that matter) is run from the Start Menu under Windows. So here is what I did, and it works for .class files run from outside a JAR just as well as it works for a JAR. (I only tested it under Windows 7.)

try {
    //Attempt to get the path of the actual JAR file, because the working directory is frequently not where the file is.
    //Example: file:/D:/all/Java/TitanWaterworks/TitanWaterworks-en.jar!/TitanWaterworks.class
    //Another example: /D:/all/Java/TitanWaterworks/TitanWaterworks.class
    PROGRAM_DIRECTORY = getClass().getClassLoader().getResource("TitanWaterworks.class").getPath(); // Gets the path of the class or jar.
    
    //Find the last ! and cut it off at that location. If this isn't being run from a jar, there is no !, so it'll cause an exception, which is fine.
    try {
        PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('!'));
    } catch (Exception e) { }
    
    //Find the last / and cut it off at that location.
    PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('/') + 1);
    //If it starts with /, cut it off.
    if (PROGRAM_DIRECTORY.startsWith("/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(1, PROGRAM_DIRECTORY.length());
    //If it starts with file:/, cut that off, too.
    if (PROGRAM_DIRECTORY.startsWith("file:/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(6, PROGRAM_DIRECTORY.length());
} catch (Exception e) {
    PROGRAM_DIRECTORY = ""; //Current working directory instead.
}

Solution 5 - Java

if netclient.p is inside a JAR file, it won't have a path because that file is located inside other file. in that case, the best path you can have is really file:/path/to/jarfile/bot.jar!/config/netclient.p.

Solution 6 - Java

This is same code from user Tombart with stream flush and close to avoid incomplete temporary file content copy from jar resource and to have unique temp file names.

File file = null;
String resource = "/view/Trial_main.html" ;
URL res = getClass().getResource(resource);
if (res.toString().startsWith("jar:")) {
	try {
		InputStream input = getClass().getResourceAsStream(resource);
		file = File.createTempFile(new Date().getTime()+"", ".html");
		OutputStream out = new FileOutputStream(file);
		int read;
		byte[] bytes = new byte[1024];

		while ((read = input.read(bytes)) != -1) {
			out.write(bytes, 0, read);
		}
		out.flush();
		out.close();
		input.close();
		file.deleteOnExit();
	} catch (IOException ex) {
		ex.printStackTrace();
	}
} else {
	//this will probably work in your IDE, but not from a JAR
	file = new File(res.getFile());
}
	     

Solution 7 - Java

You need to understand the path within the jar file.
Simply refer to it relative. So if you have a file (myfile.txt), located in foo.jar under the \src\main\resources directory (maven style). You would refer to it like:

src/main/resources/myfile.txt

If you dump your jar using jar -tvf myjar.jar you will see the output and the relative path within the jar file, and use the FORWARD SLASHES.

Solution 8 - Java

In my case, I have used a URL object instead Path.

File

File file = new File("my_path");
URL url = file.toURI().toURL();

Resource in classpath using classloader

URL url = MyClass.class.getClassLoader().getResource("resource_name")

When I need to read the content, I can use the following code:

InputStream stream = url.openStream();

And you can access the content using an InputStream.

Solution 9 - Java

A File is an abstraction for a file in a filesystem, and the filesystems don't know anything about what are the contents of a JAR.

Try with an URI, I think there's a jar:// protocol that might be useful for your purpouses.

Solution 10 - Java

follow code!

/src/main/resources/file

streamToFile(getClass().getClassLoader().getResourceAsStream("file"))

public static File streamToFile(InputStream in) {
    if (in == null) {
        return null;
    }

    try {
        File f = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
        f.deleteOnExit();

        FileOutputStream out = new FileOutputStream(f);
        byte[] buffer = new byte[1024];

        int bytesRead;
        while ((bytesRead = in.read(buffer)) != -1) {
            out.write(buffer, 0, bytesRead);
        }

        return f;
    } catch (IOException e) {
        LOGGER.error(e.getMessage(), e);
        return null;
    }
}

Solution 11 - Java

The following path worked for me: classpath:/path/to/resource/in/jar

Solution 12 - Java

private static final String FILE_LOCATION = "com/input/file/somefile.txt";

//Method Body


InputStream invalidCharacterInputStream = URLClassLoader.getSystemResourceAsStream(FILE_LOCATION);

Getting this from getSystemResourceAsStream is the best option. By getting the inputstream rather than the file or the URL, works in a JAR file and as stand alone.

Solution 13 - Java

It may be a little late but you may use my library KResourceLoader to get a resource from your jar:

File resource = getResource("file.txt")

Solution 14 - Java

When in a jar file, the resource is located absolutely in the package hierarchy (not file system hierarchy). So if you have class com.example.Sweet loading a resource named ./default.conf then the resource's name is specified as /com/example/default.conf.

But if it's in a jar then it's not a File ...

Solution 15 - Java

Inside your ressources folder (java/main/resources) of your jar add your file (we assume that you have added an xml file named imports.xml), after that you inject ResourceLoader if you use spring like bellow

@Autowired
private ResourceLoader resourceLoader;

inside tour function write the bellow code in order to load file:

    Resource resource = resourceLoader.getResource("classpath:imports.xml");
    try{
        File file;
        file = resource.getFile();//will load the file
...
    }catch(IOException e){e.printStackTrace();}

Solution 16 - Java

Maybe this method can be used for quick solution.

public class TestUtility
{ 
    public static File getInternalResource(String relativePath)
    {
        File resourceFile = null;
        URL location = TestUtility.class.getProtectionDomain().getCodeSource().getLocation();
        String codeLocation = location.toString();
        try{
            if (codeLocation.endsWith(".jar"){
                //Call from jar
                Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
                resourceFile = path.toFile();
            }else{
                //Call from IDE
                resourceFile = new File(TestUtility.class.getClassLoader().getResource(relativePath).getPath());
            }
        }catch(URISyntaxException ex){
            ex.printStackTrace();
        }
        return resourceFile;
    }
}

Solution 17 - Java

This Class function can get absolute file path by relative file path in .jar file.


public class Utility {

	public static void main(String[] args) throws Exception {
		Utility utility = new Utility();
		String absolutePath = utility.getAbsolutePath("./absolute/path/to/file");
  	}

	public String getAbsolutePath(String relativeFilePath) throws IOException {
		URL url = this.getClass().getResource(relativeFilePath);
		return url.getPath();
	}
}

If target file is same directory with Utility.java, your input will be ./file.txt.

When you input only / on getAbsolutePath(), it returns /Users/user/PROJECT_NAME/target/classes/. This means you can select the file like this /com/example/file.txt.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionno_ripcordView Question on Stackoverflow
Solution 1 - JavaNeal MaloneyView Answer on Stackoverflow
Solution 2 - JavaTombartView Answer on Stackoverflow
Solution 3 - JavaManojkumar KhoteleView Answer on Stackoverflow
Solution 4 - JavaDeProgrammerView Answer on Stackoverflow
Solution 5 - Javacd1View Answer on Stackoverflow
Solution 6 - JavaBruceView Answer on Stackoverflow
Solution 7 - Javaeric manleyView Answer on Stackoverflow
Solution 8 - JavajmgoyescView Answer on Stackoverflow
Solution 9 - JavafortranView Answer on Stackoverflow
Solution 10 - JavaseunggabiView Answer on Stackoverflow
Solution 11 - JavaAnatolyView Answer on Stackoverflow
Solution 12 - JavaShanoView Answer on Stackoverflow
Solution 13 - JavaLamberto BastiView Answer on Stackoverflow
Solution 14 - JavaVilnis KruminsView Answer on Stackoverflow
Solution 15 - JavaBERGUIGA Mohamed AmineView Answer on Stackoverflow
Solution 16 - JavagbiiView Answer on Stackoverflow
Solution 17 - JavaNoriView Answer on Stackoverflow