简体   繁体   中英

Java : getClass().getResource().toURI() Vs getClass().getResourceAsStream()

I have a java multiple modules sbt project and some of them contains a resources folder.

module-1
  resources
    template.xls
module-2
  resources
    other.xls

After packaging I got:

lib/module-1.jar
lib/module-2.jar

And I run my program like any other java application: java -cp "lib/*" MainClass .

My problem is accessing the template.xls from module-2.jar .

At first, I've tried the lines below to get my template:

URI template = getClass().getResource("/template.xls").toURI();
Files.newInputStream(Paths.get(template), StandardOpenOption.READ);

In development mode it works. But not on the server (after deployment), it cannot find the resource.

java.nio.file.FileSystemNotFoundException: null [jar:file:/.../lib/module-1.jar./template.xls]

After some research I modified my accessing code like the following to get it works in both modes (development and deployed):

InputStream templateIS = getClass().getResourceAsStream("/template.xls");

I cannot understand why !

What is the difference between the two methods?

Files.newInputStream , as the name suggests, can open files. It cannot open anything else. It's just for files.

The concept of an InputStream is much more abstract. When you open a file for reading, you get an inputstream, yup. But you also get inputstreams for many other things: Reading from a network connection; reading the unpacked contents of zip files. Reading the output of a decryption operation. The name says it all really: It's input, and it's a stream of data. Which applies to so much more than 'file on a filesystem'.

Paths.get(template) produces a path object, which represents a file on the file system. If template is derived from a URI, this does not work unless the URI that you have so happens to be a URI to a file object; most URIs are not to file objects.

Putting it all together, in your first sample, you find a resource on the classpath (which can be files, but don't have to be. For example, they could be entries in a jar file), you then ask its URI, feed it to the Paths API to turn it into a Path object, and then ask the Files API to turn this into an InputStream, which only works if the URI represents a file.

In the second snippet, you just ask the classloader system to get you an inputstream. It knows how to do that (after all, java has to load those class files.), If the resource you're asking for so happens to be represented by a file, it's going to do, internally: more or less the same thing as your first snippet. Use the Files API to open the file for reading, But if it's anything else, it knows how to do that too – it also knows how to get resources across a network, from inside jar files, generated on-the-fly – the concept of class loading (which is what class.getResource lets you access) is abstracted away.

NB: You're using it wrong. The proper way is ClassYouAreWritingIn.class.getResource and ClassYouAreWritingIn.class.getResourceAsStream ; getClass().getResource is not correct; that breaks when subclassing, whereas the correct form doesn't.

Your first scenario doesn't work because the template.xls is packaged within a jar file. It's not a file on the filesystem (whereas it likely is in your development env prior to packaging as a file). As such the Files API can't find it.

Class.getResourceAsStream() makes use of the classloading mechanism, and the class (obviously) is loaded from the .jar file.

From docs ,

The method getResource() returns a URL for the resource. The URL (and its representation) is specific to the implementation and the JVM (that is, the URL obtained in one runtime instance may not work in another). Its protocol is usually specific to the ClassLoader loading the resource. If the resource does not exist or is not visible due to security considerations, the methods return null.

If the client code wants to read the contents of the resource as an InputStream, it can apply the openStream() method on the URL. This is common enough to justify adding getResourceAsStream() to Class and ClassLoader. getResourceAsStream() the same as calling getResource().openStream(), except that getResourceAsStream() catches IO exceptions returns a null InputStream.

So, getResourceAsStream() the same as calling getResource().openStream() , except that getResourceAsStream() catches IO exceptions returns a null InputStream.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM