以不同的方式将文件作为InputStream加载
有什么区别:
InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName)
和
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
和
InputStream is = this.getClass().getResourceAsStream(fileName)
什么时候比其他人更适合使用?
我想要读取的文件在类path中作为我的类读取文件。 我的类和文件位于同一个jar文件中,并打包在一个EAR文件中,并部署在WebSphere 6.1中。
关于如何传递的fileName
有细微的差别。 基本上,你有2种不同的方法: ClassLoader.getResourceAsStream()
和Class.getResourceAsStream()
。 这两种方法将以不同的方式查找资源。
在Class.getResourceAsStream(path)
,该path被解释为本地path到您正在调用它的类的包。 例如调用, String.getResourceAsStream("myfile.txt")
将在您的类path中的以下位置查找文件: "java/lang/myfile.txt"
。 如果你的path以/
开始,那么它将被视为一个绝对path,并将从类path的根开始search。 因此,调用String.getResourceAsStream("/myfile.txt")
将查看类path./myfile.txt
中的以下位置。
ClassLoader.getResourceAsStream(path)
将所有path视为绝对path。 因此,调用String.getClassLoader().getResourceAsStream("myfile.txt")
和String.getClassLoader().getResourceAsStream("/myfile.txt")
将在以下位置的类path中查找文件: ./myfile.txt
。
每次我在这篇文章中提到一个位置,它都可能是文件系统本身的一个位置,或者是相应的jar文件中的位置,具体取决于您要从中加载资源的Class和/或ClassLoader。
在你的情况下,你从Application Server中加载类,所以你应该使用Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
而不是this.getClass().getClassLoader().getResourceAsStream(fileName)
。 this.getClass().getResourceAsStream()
也将工作。
请阅读这篇文章 ,了解关于这个问题的更多详细信息。
警告Tomcat 7及以下用户
对这个问题的答案之一表明,我的解释似乎是不正确的Tomcat的7.我试图环顾四周,看看为什么会是这样的。
所以我查看了Tomcat的几个版本Tomcat的WebAppClassLoader
的源代码。 在Tomcat 6和Tomcat 7中, findResource(String name)
(它完全负责生成所请求资源的URL)的实现实际上是相同的,但是在Tomcat 8中是不同的。
在版本6和7中,实现不会尝试规范化资源名称。 这意味着在这些版本中, classLoader.getResourceAsStream("/resource.txt")
可能不会产生与classLoader.getResourceAsStream("resource.txt")
事件相同的结果,尽pipe它应该(因为Javadoc指定的)。 [源代码]
然而,在版本8中,资源名称是标准化的,以确保资源名称的绝对版本是所使用的。 因此,在Tomcat 8中,上述两个调用应始终返回相同的结果。 [源代码]
因此,在8以前的Tomcat版本上使用ClassLoader.getResourceAsStream()
或Class.getResourceAsStream()
时,必须特别小心。还必须记住, class.getResourceAsStream("/resource.txt")
实际上调用classLoader.getResourceAsStream("resource.txt")
(前导/
被剥离)。
使用MyClass.class.getClassLoader().getResourceAsStream(path)
加载与您的代码相关的资源。 使用MyClass.class.getResourceAsStream(path)
作为快捷方式,并将资源打包到你的类的包中。
使用Thread.currentThread().getContextClassLoader().getResourceAsStream(path)
来获取作为客户端代码的一部分的资源,而不是紧挨着调用代码。 你应该小心,因为线程上下文类加载器可以指向任何东西。
普通的旧Java 7上的简单的旧Java,没有其他的依赖关系certificate了区别…
我把c:\ temp \中的file.txt放到classpath中,并把c:\ temp \放到classpath中。
这两个电话之间只有一个不同的情况。
class J { public static void main(String[] a) { // as "absolute" // ok System.err.println(J.class.getResourceAsStream("/file.txt") != null); // pop System.err.println(J.class.getClassLoader().getResourceAsStream("/file.txt") != null); // as relative // ok System.err.println(J.class.getResourceAsStream("./file.txt") != null); // ok System.err.println(J.class.getClassLoader().getResourceAsStream("./file.txt") != null); // no path // ok System.err.println(J.class.getResourceAsStream("file.txt") != null); // ok System.err.println(J.class.getClassLoader().getResourceAsStream("file.txt") != null); } }
这里的所有答案,以及这个问题的答案都表明,加载绝对URL,比如“/foo/bar.properties”,通过class.getResourceAsStream(String)
和class.getClassLoader().getResourceAsStream(String)
处理。getResourceAsStream class.getClassLoader().getResourceAsStream(String)
。 这不是这种情况,至less不是我的Tomcatconfiguration/版本(目前是7.0.40)。
MyClass.class.getResourceAsStream("/foo/bar.properties"); // works! MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!
对不起,我绝对没有令人满意的解释,但我猜测,tomcat与类加载程序做脏伎俩和黑魔法,造成差异。 我以前总是使用class.getResourceAsStream(String)
,并没有任何问题。
PS:我也在这里发布
它工作,试试这个:
InputStream in_s1 = TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml");