有什么区别:

InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName)

and

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)

and

InputStream is = this.getClass().getResourceAsStream(fileName)

什么时候每一个都比其他的更适合使用?

我想要读取的文件在类路径中,作为读取该文件的类。我的类和文件在同一个jar中,打包在一个EAR文件中,并部署在WebSphere 6.1中。


在如何解释您传递的fileName方面存在微妙的差异。基本上,你有2个不同的方法:ClassLoader.getResourceAsStream()和Class.getResourceAsStream()。这两种方法将以不同的方式定位资源。

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.

getresourceasstream (path)将认为所有路径都是绝对路径。因此调用String.class.getClassLoader(). getresourceasstream ("myfile.txt")和String.class.getClassLoader(). getresourceasstream ("/myfile.txt")都将在类路径中查找以下位置的文件:./myfile.txt。

每次我在这篇文章中提到一个位置,它可能是文件系统本身中的一个位置,也可能是对应的jar文件中的一个位置,这取决于你从Class和/或ClassLoader中加载资源。

在你的情况下,你从一个应用服务器加载类,所以你应该使用Thread.currentThread(). getcontextclassloader (). getresourceasstream (fileName)而不是this.getClass(). getclassloader (). getresourceasstream (fileName)。this.getClass(). getresourceasstream()也可以工作。

阅读这篇文章可以获得关于这个特定问题的更详细信息。


对Tomcat 7及以下用户的警告

这个问题的一个答案表明,我对Tomcat 7的解释似乎是不正确的。我试着四处看看为什么会这样。

因此,我查看了Tomcat的WebAppClassLoader的几个版本的源代码。findResource(字符串名称)的实现(最终负责生成请求资源的URL)在Tomcat 6和Tomcat 7中实际上是相同的,但在Tomcat 8中有所不同。

在版本6和7中,实现不尝试规范化资源名。这意味着在这些版本中,classLoader.getResourceAsStream("/resource.txt")可能不会产生与classLoader.getResourceAsStream("resource.txt")事件相同的结果,尽管它应该(因为这是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)来获取属于客户端代码的资源,而不是与调用代码紧密绑定的资源。你应该小心这一点,因为线程上下文类装入器可能指向任何东西。


这里所有这些答案,以及这个问题的答案,都建议加载绝对url,比如“/foo/bar”。class.getResourceAsStream(String)和class.getClassLoader(). getresourceasstream (String)处理相同。但事实并非如此,至少在我的Tomcat配置/版本(当前为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");

在普通的Java 7上使用普通的Java,没有其他依赖关系,这说明了区别……

我把file.txt放在c:\temp\中,然后把c:\temp\放在类路径中。

只有一种情况下,这两个调用之间有区别。

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); 
  }
}

在尝试了一些加载文件的方法都没有成功之后,我想起来我可以使用FileInputStream,它工作得很好。

InputStream is = new FileInputStream("file.txt");

这是另一种将文件读入InputStream的方法,它从当前运行的文件夹中读取文件。