之间有什么区别:
InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName)
和
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
和
InputStream is = this.getClass().getResourceAsStream(fileName)
什么时候每个人比其他人更合适?
我要读取的文件作为读取文件的类在类路径中。我的类和文件位于同一jar中,并打包在EAR文件中,并部署在WebSphere 6.1中。
最佳答案
关于所传递的fileName
的解释方式有细微的差异。基本上,您有2种不同的方法:ClassLoader.getResourceAsStream()
和Class.getResourceAsStream()
。这两种方法将以不同的方式定位资源。
在Class.getResourceAsStream(path)
中,该路径被解释为从中调用该类的包的本地路径。例如,调用String.class.getResourceAsStream("myfile.txt")
将在您的类路径中的以下位置查找文件:"java/lang/myfile.txt"
。如果您的路径以/
开头,那么它将被视为绝对路径,并且将从类路径的根开始搜索。因此,调用String.class.getResourceAsStream("/myfile.txt")
将在类路径./myfile.txt
中查看以下位置。ClassLoader.getResourceAsStream(path)
将所有路径视为绝对路径。因此,调用String.class.getClassLoader().getResourceAsStream("myfile.txt")
和String.class.getClassLoader().getResourceAsStream("/myfile.txt")
都会在您的类路径中的以下位置查找文件:./myfile.txt
。
每当我在这篇文章中提到一个位置时,它可能是您文件系统本身中的一个位置,也可能是相应的jar文件中的一个位置,具体取决于您从中加载资源的Class和/或ClassLoader。
在您的情况下,您是从Application Server加载类,因此您应该使用Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
而不是this.getClass().getClassLoader().getResourceAsStream(fileName)
。 this.getClass().getResourceAsStream()
也将起作用。
阅读this article以获取有关该特定问题的更多详细信息。
对Tomcat 7及更低版本用户的警告
该问题的答案之一表明,对于Tomcat 7,我的解释似乎是不正确的。我试图四处看看,为什么会这样。
因此,我研究了Tomcat几个版本的Tomcat WebAppClassLoader
的源代码。 findResource(String name)
的实现(最终负责产生所请求资源的URL)在Tomcat 6和Tomcat 7中几乎相同,但在Tomcat 8中则不同。
在版本6和7中,该实现不尝试标准化资源名称。这意味着在这些版本中,classLoader.getResourceAsStream("/resource.txt")
可能不会产生与classLoader.getResourceAsStream("resource.txt")
事件相同的结果(因为Javadoc指定了)。 [source code]
但是,在版本8中,对资源名称进行了规范化,以确保资源名称的绝对版本是所使用的版本。因此,在Tomcat 8中,上述两个调用应始终返回相同的结果。 [source code]
因此,在早于8的Tomcat版本上使用ClassLoader.getResourceAsStream()
或Class.getResourceAsStream()
时,您必须格外小心。您还必须牢记class.getResourceAsStream("/resource.txt")
实际上会调用classLoader.getResourceAsStream("resource.txt")
(剥离了最主要的/
)。