Different ways of loading a file as an InputStream

inputstream, java

Solution

There are subtle differences as to how the `fileName` you are passing is interpreted. Basically, you have 2 different methods: `ClassLoader.getResourceAsStream()` and `Class.getResourceAsStream()`. These two methods will locate the resource differently.

In `Class.getResourceAsStream(path)`, the path is interpreted as a path local to the package of the class you are calling it from. For example calling, `String.class.getResourceAsStream("myfile.txt")` will look for a file in your classpath at the following location: `"java/lang/myfile.txt"`. If your path starts with a `/`, then it will be considered an absolute path, and will start searching from the root of the classpath. So calling `String.class.getResourceAsStream("/myfile.txt")` will look at the following location in your class path `./myfile.txt`.

`ClassLoader.getResourceAsStream(path)` will consider all paths to be absolute paths. So calling `String.class.getClassLoader().getResourceAsStream("myfile.txt")` and `String.class.getClassLoader().getResourceAsStream("/myfile.txt")` will both look for a file in your classpath at the following location: `./myfile.txt`.

Everytime I mention a location in this post, it could be a location in your filesystem itself, or inside the corresponding jar file, depending on the Class and/or ClassLoader you are loading the resource from.

In your case, you are loading the class from an Application Server, so your should use `Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)` instead of `this.getClass().getClassLoader().getResourceAsStream(fileName)`. `this.getClass().getResourceAsStream()` will also work.

Read this article for more detailed information about that particular problem.

Warning for users of Tomcat 7 and below

One of the answers to this question states that my explanation seems to be incorrect for Tomcat 7. I've tried to look around to see why that would be the case.

So I've looked at the source code of Tomcat's `WebAppClassLoader` for several versions of Tomcat. The implementation of `findResource(String name)` (which is utimately responsible for producing the URL to the requested resource) is virtually identical in Tomcat 6 and Tomcat 7, but is different in Tomcat 8.

In versions 6 and 7, the implementation does not attempt to normalize the resource name. This means that in these versions, `classLoader.getResourceAsStream("/resource.txt")` may not produce the same result as `classLoader.getResourceAsStream("resource.txt")` event though it should (since that what the Javadoc specifies). [source code]

In version 8 though, the resource name is normalized to guarantee that the absolute version of the resource name is the one that is used. Therefore, in Tomcat 8, the two calls described above should always return the same result. [source code]

As a result, you have to be extra careful when using `ClassLoader.getResourceAsStream()` or `Class.getResourceAsStream()` on Tomcat versions earlier than 8. And you must also keep in mind that `class.getResourceAsStream("/resource.txt")` actually calls `classLoader.getResourceAsStream("resource.txt")` (the leading `/` is stripped).

Problem

What's the difference between: ``` InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName) ``` and ``` InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName) ``` and ``` InputStream is = this.getClass().getResourceAsStream(fileName) ``` When are each one more appropriate to use than the others? The file that I want to read is in the classpath as my class that reads the file. My class and the file are in the same jar and packaged up in an EAR file, and deployed in WebSphere 6.1.

Original source

Related problems