i want my jar file to access some files from itself. I know how to do this for BufferedImage but this doesn't work for other files. All i want is to extract some zips from my jar. i made a class folder in eclipse, put the zips inside and used
public File getResFile(String name){
return new File(getClass().getResource(name).getFile());
}
to get the File instance and extract it. it works fine in eclipse, but as soon as i export it to a jar it says
Exception in thread "main" java.io.FileNotFoundException: file:\C:\Users\DeLL\Desktop\BoxcraftClient\ClientInstaller.jar!\client.bxc (The filename, directory name, or volume label syntax is incorrect)
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(ZipFile.java:220)
at java.util.zip.ZipFile.<init>(ZipFile.java:150)
at java.util.zip.ZipFile.<init>(ZipFile.java:164)
at Launcher.install(Launcher.java:43)
at Launcher.main(Launcher.java:33)
Im working to fix this already something like 6 hours and can't find a solution. Please help!
There is a reason why getResource() returns a URL, and not a File, because the resource may not be a file, and since your code is packaged in the Jar file, it's not a file but a zip entry.
The only safe way to read the content of the resource, is as an InputStream, either by calling getResourceAsStream() or by calling openStream() on the returned URL.
first check your class path using java System.out.println("classpath is: " + System.getProperty("java.class.path")); to see if the classpath has your jar file.
And then use the getclass().classloader.getResourceAsStream(name). See if the returned URL is correct. Call the method isFile() on the URL to check if the URL is actually a file. And then call the getFile() method.
Use one of these methods, from the class Class
- getResource(java.lang.String)
- getResourceAsStream(java.lang.String)
this.getClass().getResource(name);
this.getClass().getResourceAsStream(name);
Warning: By default it loads the file from the location, where the this.class, is found in the package. So if using it from a class org.organisation.project.App, then the file need to be inside the jar in the directory org/organisation/project. In case the file is located in the root, or some other directory, inside the jar, use the /, in from of the file name. Like /data/names.json.
Use Spring's PathMatchingResourcePatternResolver;
It will do the trick for both launching the package from an IDE or from the file system:
public List<String> getAllClassesInRunningJar() throws Exception {
try {
List<String> list = new ArrayList<String>();
// Get all the classes inside the package com.my.package:
// This will do the work for both launching the package from an IDE or from the file system:
String scannedPackage = "com.my.package.*";
// This is spring - org.springframework.core; use these imports:
// import org.springframework.core.io.Resource;
// import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
Resource[] resources = scanner.getResources(scannedPackage.replace(".", "/"));
for (Resource resource : resources)
list.add(resource.getURI().toString());
return list ;
} catch (Exception e) {
throw new Exception("Failed to get the classes: " + e.getMessage(), e);
}
}
Related
This question already has answers here:
Java Jar file: use resource errors: URI is not hierarchical
(6 answers)
Closed 6 years ago.
I have files in resource folder. For example if I need to get file from resource folder, I do like that:
File myFile= new File(MyClass.class.getResource(/myFile.jpg).toURI());
System.out.println(MyClass.class.getResource(/myFile.jpg).getPath());
I've tested and everything works!
The path is
/D:/java/projects/.../classes/X/Y/Z/myFile.jpg
But, If I create jar file, using , Maven:
mvn package
...and then start my app:
java -jar MyJar.jar
I have that following error:
Exception in thread "Thread-4" java.lang.RuntimeException: ხელმოწერის განხორციელება შეუძლებელია
Caused by: java.lang.IllegalArgumentException: URI is not hierarchical
at java.io.File.<init>(File.java:363)
...and path of file is:
file:/D:/java/projects/.../target/MyJar.jar!/X/Y/Z/myFile.jpg
This exception happens when I try to get file from resource folder. At this line. Why? Why have that problem in JAR file? What do you think?
Is there another way, to get the resource folder path?
You should be using
getResourceAsStream(...);
when the resource is bundled as a jar/war or any other single file package for that matter.
See the thing is, a jar is a single file (kind of like a zip file) holding lots of files together. From Os's pov, its a single file and if you want to access a part of the file(your image file) you must use it as a stream.
Documentation
Here is a solution for Eclipse RCP / Plugin developers:
Bundle bundle = Platform.getBundle("resource_from_some_plugin");
URL fileURL = bundle.getEntry("files/test.txt");
File file = null;
try {
URL resolvedFileURL = FileLocator.toFileURL(fileURL);
// We need to use the 3-arg constructor of URI in order to properly escape file system chars
URI resolvedURI = new URI(resolvedFileURL.getProtocol(), resolvedFileURL.getPath(), null);
File file = new File(resolvedURI);
} catch (URISyntaxException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
It's very important to use FileLocator.toFileURL(fileURL) rather than resolve(fileURL)
, cause when the plugin is packed into a jar this will cause Eclipse to create an unpacked version in a temporary location so that the object can be accessed using File. For instance, I guess Lars Vogel has an error in his article - http://blog.vogella.com/2010/07/06/reading-resources-from-plugin/
I face same issue when I was working on a project in my company. First Of All, The URI is not hierarichal Issue is because probably you are using "/" as file separator.
You must remember that "/" is for Windows and from OS to OS it changes, It may be different in Linux. Hence Use File.seperator .
So using
this.getClass().getClassLoader().getResource("res"+File.separator+"secondFolder")
may remove the URI not hierarichal. But Now you may face a Null Pointer Exception. I tried many different ways and then used JarEntries Class to solve it.
File jarFile = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
String actualFile = jarFile.getParentFile().getAbsolutePath()+File.separator+"Name_Of_Jar_File.jar";
System.out.println("jarFile is : "+jarFile.getAbsolutePath());
System.out.println("actulaFilePath is : "+actualFile);
final JarFile jar = new JarFile(actualFile);
final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
System.out.println("Reading entries in jar file ");
while(entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
final String name = jarEntry.getName();
if (name.startsWith("Might Specify a folder name you are searching for")) { //filter according to the path
System.out.println("file name is "+name);
System.out.println("is directory : "+jarEntry.isDirectory());
File scriptsFile = new File(name);
System.out.println("file names are : "+scriptsFile.getAbsolutePath());
}
}
jar.close();
You have to specify the jar name here explicitly. So Use this code, this will give you directory and sub directory inside the folder in jar.
With reference to the link: How do I read a resource file from a Java jar file?
I am trying using your code base and trying to read content of sample.csv which is residing in my project directory src/main/resources. I am unable to read the content, it says can not read file. Output:
[Can not read file: sample.csv]
//This is added within your while loop after this check /* If it is a directory, then skip it. */
I mean when file is detected then next is my below code snippet added to read the file content
if(entry.getName().contains("sample.csv")) {
File f1 = new File("sample.csv");
if(f1.canRead()) {
List<String> lines = Files.readAllLines(f1.toPath());
System.out.println("Lines in file: "+lines.size());
} else {
System.out.println("Can not read file: "+entry.getName());
}
}
Can anyone educate me what I am doing wrong here, how can I make it working?
My requirement is this:
(My micro-service) Service.jar imports Parser.jar library in its pom.xml
(My library) - Parser.jar has FnmaUtils-3.2-fieldMapping.csv file in src/main/resources directory
There is a FnmaUtils class that loads the FnmaUtils-3.2-fieldMapping.csv within its constructor, this class is part of Parser.jar - Here I am trying to read the content FnmaUtils-3.2-fieldMapping.csv, this step is keep failing with below error, tried all possible options shown in [How do I read a resource file from a Java jar file?
public FnmaUtils() {
String mappingFileUrl = null;
try {
Resource resource = new ClassPathResource("FnmaUtils-3.2-fieldMapping.csv");
mappingFileUrl = resource.getFile().getPath();
loadFnmaTemplate(mappingFileUrl);
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("Error loading fnma template file ", e);
}
}
Getting error:
java.io.FileNotFoundException: class path resource [`FnmaUtils-3.2-fieldMapping.csv`] cannot be resolved to absolute file path because it does not reside in the file system: `jar:file:/home/ravibeli/.m2/repository/com/xxx/mismo/util/fnma-parser32/2018.1.0.0-SNAPSHOT/fnma-parser32-2018.1.0.0-SNAPSHOT.jar!/FnmaUtils-3.2-fieldMapping.csv`
at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:218)
at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52)
at com.xxx.fnma.util.FannieMaeUtils.<init>(FannieMaeUtils.java:41)
at com.xxx.fnma.processor.FNMA32Processor.<init>(FNMA32Processor.java:54)
at com.xxx.fnma.processor.FNMA32Processor.<clinit>(FNMA32Processor.java:43)
What is going wrong here?
Try
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("SomeTextFile.txt");
Be sure the resource is in your classpath.
I am trying to load an image to use as an icon in my application. The appropriate method according to this tutorial is:
protected ImageIcon createImageIcon(String path, String description)
{
java.net.URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL, description);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
So, I placed the location of the file, and passed it as a parameter to this function. This didn't work, i.e. imgURL was null. When I tried creating the ImageIcon by passing in the path explicitly:
ImageIcon icon = new ImageIcon(path,"My Icon Image");
It worked great! So the application can pick up the image from an explicitly defined path, but didn't pick up the image using getResources(). In both cases, the value of the path variable is the same. Why wouldn't it work? How are resources found by the class loader?
Thanks.
getClass().getResource(path) loads resources from the classpath, not from a filesystem path.
You can request a path in this format:
/package/path/to/the/resource.ext
Even the bytes for creating the classes in memory are found this way:
my.Class -> /my/Class.class
and getResource will give you a URL which can be used to retrieve an InputStream.
But... I'd recommend using directly getClass().getResourceAsStream(...) with the same argument, because it returns directly the InputStream and don't have to worry about creating a (probably complex) URL object that has to know how to create the InputStream.
In short: try using getResourceAsStream and some constructor of ImageIcon that uses an InputStream as an argument.
Classloaders
Be careful if your app has many classloaders. If you have a simple standalone application (no servers or complex things) you shouldn't worry. I don't think it's the case provided ImageIcon was capable of finding it.
Edit: classpath
getResource is—as mattb says—for loading resources from the classpath (from your .jar or classpath directory). If you are bundling an app it's nice to have altogether, so you could include the icon file inside the jar of your app and obtain it this way.
As a noobie I was confused by this until I realized that the so called "path" is the path relative to the MyClass.class file in the file system and not the MyClass.java file. My IDE copies the resources (like xx.jpg, xx.xml) to a directory local to the MyClass.class. For example, inside a pkg directory called "target/classes/pkg. The class-file location may be different for different IDE's and depending on how the build is structured for your application. You should first explore the file system and find the location of the MyClass.class file and the copied location of the associated resource you are seeking to extract. Then determine the path relative to the MyClass.class file and write that as a string value with "dots" and "slashes".
For example, here is how I make an app1.fxml file available to my javafx application where the relevant "MyClass.class" is implicitly "Main.class". The Main.java file is where this line of resource-calling code is contained. In my specific case the resources are copied to a location at the same level as the enclosing package folder. That is: /target/classes/pkg/Main.class and /target/classes/app1.fxml. So paraphrasing...the relative reference "../app1.fxml" is "start from Main.class, go up one directory level, now you can see the resource".
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("../app1.fxml"));
Note that in this relative-path string "../app1.fxml", the first two dots reference the directory enclosing Main.class and the single "." indicates a file extension to follow. After these details become second nature, you will forget why it was confusing.
getResource by example:
package szb.testGetResource;
public class TestGetResource {
private void testIt() {
System.out.println("test1: "+TestGetResource.class.getResource("test.css"));
System.out.println("test2: "+getClass().getResource("test.css"));
}
public static void main(String[] args) {
new TestGetResource().testIt();
}
}
output:
test1: file:/home/szb/projects/test/bin/szb/testGetResource/test.css
test2: file:/home/szb/projects/test/bin/szb/testGetResource/test.css
getResourceAsStream() look inside of your resource folder. So the fil shold be placed inside of the defined resource-folder
i.e if the file reside in /src/main/resources/properties --> then the path should be /properties/yourFilename.
getClass.getResourceAsStream(/properties/yourFilename)
Play 2.2.3. Windows 7.
public static Result menu() throws IOException {
String path = Play.application().resource("resources/menu.json").toString();
String content = Files.toString(new File(path), Charsets.UTF_8);
return ok(content).as("JSON");
}
Got an error:
... scala-2.10\classes\resources\menu.json The filename, directory
name, or volume label syntax is incorrect
Checking that path in file-system, I'm able to find my file there:
..\target\scala-2.10\classes\resources\menu.json
I'm able to find it there. Why play can't?
--
UPDATE:
I've just figured out I can not create files on C:\ root folder on my machine. That maybe the issue. But on other hand I'm not accessing root folder, and ad trying to get read only access. And I do have write access to that file on that path anyway.
As actually you want to use your menu.json file as a static asset you can put it i.e. into public/resources/menu.json file and then read it with simple:
<script>
$.get('#routes.Assets.at("resources/menu.json")');
</script>
or just directly by request:
http://localhost:9000/assets/resources/menu.json
To do what you want via controller you need to read the InputStream by classpath (remember that finally it will be archived into jar file!) but it need to be placed in conf folder i.e.: conf/resources/menu.json then from controller:
public static Result menuViaControllerJson() {
InputStream is = Play.application().classloader().getResourceAsStream("resources/menu.json");
return (is != null)
? ok(is)
: notFound();
}
Anyway you will get exactly the same result as for common Assets.at, so consider if it's worth of effort.
Edit: If you want to use this file as custom config just use HOCON syntax file i.e.: conf/ses.conf:
foo = "bar"
and in controller:
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
....
Config cfg = ConfigFactory.parseResources(Play.application().classloader(), "ses.conf");
debug("My 'foo' is configured as: " + cfg.getString("foo"));
I am trying to explore Apache commons configuration to dynamically load the property file and do modification in the file and save it.
I wrote a demo code for the same.
Code Snippet
package ABC;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
public class Prop {
public static void main(String[] args)
{
try {
URL propertiesURL = Prop.class.getResource("/d1.properties");
if (propertiesURL == null) {
System.out.println("null");
}
String absolutePath=propertiesURL.getPath();
PropertiesConfiguration pc = new PropertiesConfiguration(absolutePath);
pc.setReloadingStrategy(new FileChangedReloadingStrategy());
String s=(String)pc.getProperty("key_account_sales");
System.out.println("s is " + s);
pc.setAutoSave(true);
pc.setProperty("key_account_sales", "Dummy");
pc.save();
System.out.println("Modified as well");
String sa=(String)pc.getProperty("key_account_sales");
System.out.println("s is " + sa);
}catch(ConfigurationException ce)
{
ce.printStackTrace();
}
}
}
Although when I run the code multiple times, the updated value for the property is being properly shown but the changes are not seen in the Property file.
I tried refreshing the entire workspace and the project but still the property file shows the previous entry whereas this code displays the updated entry in console.
Why my property file is not getting updated?
Well I noticed that a new file with same name was formed inside bin
directory of my IDE workspace. This new file contains the required
changes.
However I still want that the old file should be updated with the new
value and instead of creating a new file, it should update in the old
file itself.
My property file is located inside a Web Application package say
Dem1
by the name of
Prop1.prop
I want to read this property file from in another class say
Reading.java
located inside another package
Dem2
, do changes in this same property file and show it to another user. It is a web application being deployed on an application server.
Even after using the absolute path in a simple file (main function) it is not reflecting the changes in the same file but updating it in new file.
I am doing a very slight mistake but can someone please help.
Using absolute path I am not able to make changes in the same property file in normal main method also. Please suggest.
New file in bin directory is created instead of updating the same file
in src folder.
You should be able to solve this using absolute paths. The PropertiesConfiguration class is finding your properties file somewhere on the classpath and only knows to write back to "d1.properties"; hence you have a file appearing in your bin directory.
The absolute path can be obtained by querying resources on the classpath. Something like the following:
URL propertiesURL = Prop.class.getResource("/d1.properties");
if (propertiesURL == null) {
// uh-oh...
}
String absolutePath = propertiesURL.getPath();
// Now use absolutePath