Accessing a Java Resource as a File

2019-01-26 14:03发布

问题:

I'm trying to access a resource from the class path/JAR file as a File object. I'm aware that it's the preferred method to use an InputStream object instead, but I'm using an external library (WorldEdit) which needs a File object.

Here's my code:

InputStream templStream = "".getClass().getResourceAsStream("/res/template.prom");
System.out.println("templateStream: " + templStream.toString());
File templFile = new File("".getClass().getResource("/res/template.prom").toURI());
System.out.println("templateFile: " + templFile.canRead());

Now while I'm still inside eclipse, both ways of accessing the resource work flawlessly and produce this output:

templStream: java.io.BufferedInputStream@746d1683
templFile: true

But after exporting the code into a JAR archive, the code fails:

templStream: sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@47aa261b
Exception in thread "main" java.lang.IllegalArgumentException: URI is not hierarchical
    at java.io.File.<init>(File.java:392)
    at SMCToPROM.main(SMCToPROM.java:101)

So I've been, without success, searching for a way for either accessing the resource as a File directly, or going the way of using an InputStream and converting that InputStream to a file.

The worst case fallback solution would be to copy the InputStream to a file on the filesystem, and then open that file, but I hope that won't be neccesary.

回答1:

The short answer is that you can't, because the resource isn't a File.

Either the third-party library is badly written if all it wants to do is read data from a source (and thus it should take an InputStream), or the library actually wants to do File-specific manipulations.

Assuming this isn't an oversight in the library that can be fixed, you'll need to actually create a file yourself. Try calling File.createTempFile(), populate this file with the contents of the resource yourself, and then pass this File object to the library. (Delete it once you're done, of course).



回答2:

You cannot access the jarred resources as Files directly. Instead you need to copy the content of the resource to an actual file and pass that to the 3rd party library (you can use the InputStream you get from getResourceAsInputStream() for this)



回答3:

You could write a File wrapper object that is backed by an InputStream, Byte Array or ByteBuffer and then pass that into the poorly written library code.

This won't be simple and would require you writing a correct implementation of every method if you have no idea what methods that library is calling on the File object.

I did this once in a similar situation, but I knew the sub-set of calls and didn't have to implement every method correctly. You might get lucky and the only thing the library does is call .getInputStream() and be done with it easily.