[顶]Different ways of loading a file as an InputStream

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.

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.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.getResourceAsStream("/myfile.txt") will look at the following location in your class path ./myfile.txt.
这就是Class.getResourceAsStream(path)让你疑惑的地方,/开头不是代表系统的根目录。
ClassLoader.getResourceAsStream(path) will consider all paths to be absolute paths. So calling String.getClassLoader().getResourceAsString("myfile.txt") and String.getClassLoader().getResourceAsString("/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.

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).

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.

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).

I’m pretty sure that getClass().getResourceAsStream("/myfile.txt") behaves differently from getClassLoader().getResourceAsStream("/myfile.txt").

They don’t behave differenty. Actually, the javadoc for Class.getResourceAsStream(String) says the following thing: “This method delegates to this object’s class loader.”, and then gives a bunch of rules on how it converts a relative path to an absolute path before delegating to the classloader.
Look at the actual source. Class.getResourceAsStream strips off the leading forward slash if you provide an absolute path.
Which makes it behave exactly the same as ClassLoader.getResourceAsStream() since the latter interprets all paths as absolute, whether they start with a leading slash or not. So as long as you path is absolute, both methods behave identically. If your path is relative, then the behavior is different.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值