- java — How to list directories in resources in jar
- 4 Answers 4
- How to get a path to a resource in a Java JAR file
- Pass Resources Folder path to the command when running a jar
- How to get file path to a resource inside a jar
- Jar File can’t find image file path
- Using toURI() and toString()
- Using toExternalForm()
- Using File and toURI()
- Summary
java — How to list directories in resources in jar
Although I found many answers how to list file resources, I am stuck to find a way how to list all direct subdirectories of a directory (or path) in resources, that would work when app is run both from IDE (IntelliJ) and jar.
The goal is to get names of subdirectories of directory «dir1»: subdir1, subdir2
Thread.currentThread().getContextClassLoader().getResourceAsStream("dir1");
and to use returned InputStream (containing names of subdirectories), but does not work from jar. Works from IntelliJ.
I also tried to use spring framework but
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources("dir1/*");
does not work as well from jar — resources array is empty. Works from IntelliJ.
Resource[] resources = resolver.getResources("dir1/*/");
and it works from jar, but does not work from IntelliJ.
When I make it work from jar, I break the other way and vice versa. My last idea is to use
Resource[] resources = resolver.getResources("dir1/**");
to get all resources under the directory and then get only ones that are required. Is there a better (preferably not hacky) way?
4 Answers 4
Seems like the following works:
public String[] getResourcesNames(String path) < try < URL url = getClassLoader().getResource(path); if (url == null) < return null; >URI uri = url.toURI(); if (uri.getScheme().equals("jar")) < // Run from jar try (FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap()))< Path resourcePath = fileSystem.getPath(path); // Get all contents of a resource (skip resource itself), if entry is a directory remove trailing / ListresourcesNames = Files.walk(resourcePath, 1) .skip(1) .map(p -> < String name = p.getFileName().toString(); if (name.endsWith("/")) < name = name.substring(0, name.length() - 1); >return name; >) .sorted() .collect(Collectors.toList()); return resourcesNames.toArray(new String[resourcesNames.size()]); > > else < // Run from IDE File resource = new File(uri); return resource.list(); >> catch (IOException | URISyntaxException e) < return null; >> private ClassLoader getClassLoader()
I could solve a similar problem in Quarkus (URL scheme jar and resource for resources embedded in native binary). The trick is to uses the Path given by the FileSystem instance BEFORE closing it (try-with-resources block). Thanks.
I finally ended up with this (using spring):
public class ResourceScanner < private PathMatchingResourcePatternResolver resourcePatternResolver; public ResourceScanner() < this.resourcePatternResolver = new PathMatchingResourcePatternResolver(); >public Resource getResource(String path) < path = path.replace("\\", "/"); return resourcePatternResolver.getResource(path); >public Resource[] getResources(String path) throws IOException < path = path.replace("\\", "/"); return resourcePatternResolver.getResources(path); >public Resource[] getResourcesIn(String path) throws IOException < // Get root dir URI Resource root = getResource(path); String rootUri = root.getURI().toString(); // Search all resources under the root dir path = (path.endsWith("/")) ? path + "**" : path + "/**"; // Filter only direct children return Arrays.stream(getResources(path)).filter(resource -> < try < String uri = resource.getURI().toString(); boolean isChild = uri.length() >rootUri.length() && !uri.equals(rootUri + "/"); if (isChild) < boolean isDirInside = uri.indexOf("/", rootUri.length() + 1) == uri.length() - 1; boolean isFileInside = uri.indexOf("/", rootUri.length() + 1) == -1; return isDirInside || isFileInside; >return false; > catch (IOException e) < return false; >>).toArray(Resource[]::new); > public String[] getResourcesNamesIn(String path) throws IOException < // Get root dir URI Resource root = getResource(path); String rootUri = URLDecoder.decode(root.getURI().toString().endsWith("/") ? root.getURI().toString() : root.getURI().toString() + "/", "UTF-8"); // Get direct children names return Arrays.stream(getResourcesIn(path)).map(resource -> < try < String uri = URLDecoder.decode(resource.getURI().toString(), "UTF-8"); boolean isFile = uri.indexOf("/", rootUri.length()) == -1; if (isFile) < return uri.substring(rootUri.length()); >else < return uri.substring(rootUri.length(), uri.indexOf("/", rootUri.length() + 1)); >> catch (IOException e) < return null; >>).toArray(String[]::new); > >
Amazing that still in 2019 this was difficult to solve. Thanks for this solution, this is the only one that worked for me. The FileSystem did not work for when working with jars and running the application from command line (not IDE).
The problem with a jar is that there are not folder as such, there are entries, and folders are just entries with a trailing slash in it’s name. This is probably why dir1/*/ return the folders in jar but not from de IDE where the folder name does not end with / . For a similar reason dir1/* work on the IDE but not in the jar since again, the folder name ends with the slash in the jar.
Spring handles the resources based on files, if you try to get an empty folder as resource it will fail, and this empty folder normally is not added to the jar. Also looking for folders is not that common, since the content is in files, and the only useful information is what files it contains.
The easiest way you can achieve this is to use dir1/** pattern, since this will list all the files, and folders with files under the dir1 directory.
‘Detecting’ if the program is being executed from a jar file, to choose a different strategy to list the folders can also be done, but that solution is even more ‘hacky’.
Here an example using first option, pattern dir1/** (just in case needed):
String folderName = "dir1"; String folderPath = String.format("%s/**", folderName); Resource[] resources = resolver.getResources(folderPath); Map resourceByURI = Arrays.stream(resources) .collect(Collectors.toMap(resource -> < try < return resource.getURI().toString(); >catch (IOException e) < throw new RuntimeException(e); >>, Function.identity()));
The resourceByURI is a map containing the Resource , identified by its URI.
Resource folder = resolver.getResource(folderName); int folderLength = folder.getURI().toString().length(); Map subdirectoryByName = resourceByURI.keySet().stream() .filter(name -> name.length() > folderLength && name.indexOf("/", folderLength + 1) == name.length() - 1) .collect(Collectors.toMap(Function.identity(), name -> name.substring(folderLength, name.indexOf("/", folderLength + 1))));
Then you can get the URI of the folder, to calculate the offset of the path (similar to what spring does), then check that the name is longer that the current folder (to discard the same folder in the jar case) and that the name constains a single / in the end. Finally collect to a Map again identified by the URI, containing the name of the folders. The collection of folder names is subdirectoryByName.values() .
How to get a path to a resource in a Java JAR file
If it isn’t there, then load the default version of this file, packed into your jar, by reading it with , and write it to that location, then inform the user they can edit it there. Having a file that you write to from your own process next to your jar is a bad security practice and in general an obsolete application model, going on 20 years now.
Pass Resources Folder path to the command when running a jar
I have built a Jar File without including my resource folder. Because property file need to be edited when running the jar. But I am not aware how to pass the resources folder path along with the jar command. Current command that I use to run the jar is as follows
I also tried below command
java -jar myProject.jar -Dconfig=/a/full/path
UPDATE As I want to edit my property file before running the jar file I don’t want to embed resources folder within the jar file. I need the resources folder path to be passed to the command which used to run the jar file
Using the resources system ( MyClass.class.getResource / getResourceAsStream is the right way; commonly written as MyClass.class.getClassLoader().getResource or getClass().getResource or getClass().getClassLoader().getResource() which are all subtly wrong) is not correct for ‘mutable’ files.
If there is a properties file, then look for it in the user’s home dir ( Paths.get(System.getProperty(«user.home»), «myapp.properties») . If it isn’t there, then load the default version of this file, packed into your jar, by reading it with .getResource , and write it to that location, then inform the user they can edit it there.
Having a file that you write to from your own process next to your jar is a bad security practice and in general an obsolete application model, going on 20 years now. Directories containing executable code should not be writable except by the user themselves and admin users. An app has absolutely no business writing anything anywhere near executables. If your system even lets you, then your OS / your user settings are misconfigured. Or at the very least, assuming (i.e. forcing ) a user of a computer to run in a mode that means the processes they start can write to the place the executables live — is just bad software.
conclusion: You think you want to write to a properties file that lives next to your jar, but you don’t. Instead, write in user.home — that’s what it is for.
How to get the path and name of the current running jar?, File dir = new File(YourMainClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); String jar = System.
How to get file path to a resource inside a jar
I am trying to load a file which is in src/main/resources. It works fine in my local but when I deploy a jar , seeing an issue . I know how to get the Inputstream but in my case I need to load file.
File location:
src main resources cert truststore.ks
String filename = cert/truststore.ks
spark.sparkContext().addFile(getAbsolutePath(filename));
public String getAbsolutePath(String fileName) throws IOException, URISyntaxException
Exception in thread "main" java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.spark.deploy.worker.DriverWrapper$.main(DriverWrapper.scala:65) at org.apache.spark.deploy.worker.DriverWrapper.main(DriverWrapper.scala) Caused by: java.lang.IllegalArgumentException: java.net.URISyntaxException: Relative path in absolute URI: jar:file:/work/run/driver-20200525203940-0037/service-1.0.0-SNAPSHOT.jar!/cert/truststore.ks at org.apache.hadoop.fs.Path.initialize(Path.java:205) at org.apache.hadoop.fs.Path.(Path.java:171) at org.apache.spark.SparkContext.addFile(SparkContext.scala:1519) at org.apache.spark.SparkContext.addFile(SparkContext.scala:1499) Caused by: java.net.URISyntaxException: Relative path in absolute URI: jar:file:/work/run/driver-20200525203940-0037/service-1.0.0-SNAPSHOT.jar!/cert/truststore.ks at java.net.URI.checkPath(URI.java:1823) at java.net.URI.(URI.java:745) at org.apache.hadoop.fs.Path.initialize(Path.java:202)
For Example follow this gist
How to get spring boot application jar parent folder path dynamically?, ApplicationHome home = new ApplicationHome(MyMainSpringBootApplication.class); home.getDir(); // returns the folder where the jar is. This is
Jar File can’t find image file path
I’m creating a simple program that I now want to export as a executable jar file. Everything works fine except the jar file can’t find the image.
For creating the runnable JAR file I used the second option in Eclipse 2021-12 (Package required libraries into generated JAR). This seems to work well, because I only have the jar and no other folders I need to run the program.
My jar file structure looks like this:
jar_file/
├─ images/
│ ├─ frog.png
I’ve tried multiple ways of getting the image file.
This is how I define Icon:
private static Image icon;
Using toURI() and toString()
This does not work in Eclipse.
Path Output: file:/C:/Projekte/serviceticketapp/target/classes/images/frog.png
This does not work in the Jar File.
Path Output: rsrc:images/frog.png
Using toExternalForm()
This does not work in Eclipse.
Path Output: file:/C:/Projekte/serviceticketapp/target/classes/images/frog.png
This does not work in the Jar File.
Path Output: rsrc:images/frog.png
Using File and toURI()
File imageFile = new File(getClass().getResource(«/images/frog.png»).toURI()); icon = Toolkit.getDefaultToolkit().getImage(imageFile.getAbsolutePath());
Path Output: C:\Projekte\serviceticketapp\target\classes\images\frog.png
java.lang.IllegalArgumentException: URI is not hierarchical
Summary
Above you can see all the ways I tried to get the image file. Only one works in Eclipse and none of them work in the jar file.
What am I doing wrong or how do I have to arrange the files in order for it to work in the jar file and in Eclipse.
Please ask if you need more information. Thanks in advance.
I would use imagio ( import javax.imageio.ImageIO )
tIcon = new TrayIcon(ImageIO.read(getClass().getResource("/images/frog.png"), "Service Ticket App");
How to get filepath of the located file when ran from JAR in JAVA?, File file = getFileFromResources(«Utility/ConfigurationXML.xml»); strFilePath = file.getAbsolutePath();. which gives me the absolute path of the