Java Jar file: use resource errors: URI is not hierarchical

95,418

Solution 1

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.

Solution 2

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());

Solution 3

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/

Solution 4

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

Share:
95,418
hqt
Author by

hqt

Those who don't speak math are doomed to speak nonsense. My brief profile: https://github.com/hqt/profile

Updated on July 05, 2022

Comments

  • hqt
    hqt almost 2 years

    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
      //....
    }
    
  • hqt
    hqt about 12 years
    I have tried again your way (is my second code above), but when it is go through: in.read(buf) ---> I meet null point exception. :( @:resource is a folder in my project. it has same hierarchy with other package. So, I need I must include resource
  • dash1e
    dash1e about 12 years
    post the hierarchy of your project
  • TekTimmy
    TekTimmy over 11 years
    But what if i really NEED an "File" object... ?
  • dash1e
    dash1e over 11 years
    You cannot have a File object because a resource is not necessary a file.
  • Zarathustra
    Zarathustra over 10 years
    Could you please provide more details on that? When is a ressource not a file?
  • dash1e
    dash1e over 10 years
    When the resource is located in a jar, for example, the single resource is a Jar Entry object (not a file on file system), and cannot be used to create an instance of java.io.File class
  • Ilya Buziuk
    Ilya Buziuk almost 10 years
    @dash1e ^ This is not true - see my answer
  • Andrey
    Andrey about 9 years
    What is Platform class? Some non-rt library needed?
  • Ilya Buziuk
    Ilya Buziuk about 9 years
    @AndreyP this solution is for eclipse rcp plugin developers. I would recommend to try getResourceAsStream(...) approach
  • Daniel
    Daniel about 9 years
    it works for me without the slash: "data.sav" instead of "/data.sav"
  • dash1e
    dash1e about 9 years
    @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 /.
  • J. Katzwinkel
    J. Katzwinkel about 8 years
    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.
  • JN Gerbaux
    JN Gerbaux over 7 years
    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...
  • Rémi
    Rémi about 3 years
    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());
  • Vishal Patel
    Vishal Patel almost 3 years
    @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);