89

I have deployed my app to jar file. When I need to copy data from one file of resource to outside of jar file, I do this code:

URL resourceUrl = getClass().getResource("/resource/data.sav"); File src = new File(resourceUrl.toURI()); //ERROR HERE File dst = new File(CurrentPath()+"data.sav"); //CurrentPath: path of jar file don't include jar file name FileInputStream in = new FileInputStream(src); FileOutputStream out = new FileOutputStream(dst); // some excute code here 

The error I have met is: URI is not hierarchical. this error I don't meet when run in IDE.

If I change above code as some help on other post on StackOverFlow:

InputStream in = Model.class.getClassLoader().getResourceAsStream("/resource/data.sav"); File dst = new File(CurrentPath() + "data.sav"); FileOutputStream out = new FileOutputStream(dst); //.... byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { //NULL POINTER EXCEPTION //.... } 
0

6 Answers 6

129

You cannot do this

File src = new File(resourceUrl.toURI()); //ERROR HERE 

it is not a file! When you run from the ide you don't have any error, because you don't run a jar file. In the IDE classes and resources are extracted on the file system.

But you can open an InputStream in this way:

InputStream in = Model.class.getClassLoader().getResourceAsStream("/data.sav"); 

Remove "/resource". Generally the IDEs separates on file system classes and resources. But when the jar is created they are put all together. So the folder level "/resource" is used only for classes and resources separation.

When you get a resource from classloader you have to specify the path that the resource has inside the jar, that is the real package hierarchy.

Sign up to request clarification or add additional context in comments.

12 Comments

post the hierarchy of your project
But what if i really NEED an "File" object... ?
@Daniel it depends on where you put your resource. You can use data.sav without the starting / if you put your resource file in the same package of your class file. But in the question the data.sav is in the root package so in that case he needs to prepend /.
Just like TekTimmy: But what if I REALLY NEED a file ? I'm in a email sending process and we wanna join a logo file picture to email. The pict is in the jar and I have to give it to the datasource as a File, not an InputStream...
@JNGerbaux i also wanted a File object so i created temp File and copied content from InputStream to File object. using FileUtils.copyInputStreamToFile(inputStream, file);
|
31

If for some reason you really need to create a java.io.File object to point to a resource inside of a Jar file, the answer is here: https://stackoverflow.com/a/27149287/155167

File f = new File(getClass().getResource("/MyResource").toExternalForm()); 

Comments

12

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/

4 Comments

What is Platform class? Some non-rt library needed?
@AndreyP this solution is for eclipse rcp plugin developers. I would recommend to try getResourceAsStream(...) approach
In my maven-built RCP E4 application, jar-bundled binary files need to be extracted and opened. Your solution finally enabled me to do so and open file.getAbsolutePath() in the OS default browser.
Thanks ! This answer was very helpful, since I got a bug with FileLocator.resolve. I could create the File object directly with : File f = new File(FileLocator.toFileURL(resolvedFileURL).toURI());
1

I got a similiar issues before, and I used the code:

new File(new URI(url.toString().replace(" ","%20")).getSchemeSpecificPart()); 

instead of the code :

new File(new URI(url.toURI()) 

to solve the problem

Comments

0

While I stumbled upon this problem myself I'd like to add another option (to the otherwise perfect explanation from @dash1e):

Export the plugin as a folder (not a jar) by adding:

Eclipse-BundleShape: dir 

to your MANIFEST.MF.

At least when you export your RCP app with the export wizard (based on a *.product) file this gets respected and will produce a folder.

Comments

0

In addition to the general answers, you can get "URI is not hierarchical" from Unitils library attempting to load a dataset off a .jar file. It may happen when you keep datasets in one maven submodule, but actual tests in another.

There is even a bug UNI-197 filed.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.