232

有什么区别:

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 中。

4

6 回答 6

303

fileName关于您传递的内容的解释方式存在细微差别。基本上,您有 2 种不同的方法:ClassLoader.getResourceAsStream()Class.getResourceAsStream(). 这两种方法将以不同的方式定位资源。

Class.getResourceAsStream(path)中,路径被解释为您从中调用它的类的包的本地路径。例如调用,String.class.getResourceAsStream("myfile.txt")将在您的类路径中的以下位置查找文件:"java/lang/myfile.txt". 如果您的路径以 a 开头/,那么它将被视为绝对路径,并将从类路径的根目录开始搜索。因此,调用String.class.getResourceAsStream("/myfile.txt")将查看您的类路径中的以下位置./myfile.txt

ClassLoader.getResourceAsStream(path)将所有路径视为绝对路径。因此,调用String.class.getClassLoader().getResourceAsStream("myfile.txt")andString.class.getClassLoader().getResourceAsStream("/myfile.txt")都会在您的类路径中的以下位置查找文件:./myfile.txt.

每次我在这篇文章中提到一个位置时,它可能是您的文件系统本身中的一个位置,也可能是相应的 jar 文件中的一个位置,具体取决于您从中加载资源的类和/或类加载器。

在您的情况下,您正在从应用程序服务器加载类,因此您应该使用Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)而不是this.getClass().getClassLoader().getResourceAsStream(fileName). this.getClass().getResourceAsStream()也将工作。

阅读本文以获取有关该特定问题的更多详细信息。


Tomcat 7 及以下用户的警告

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

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

在版本 6 和 7 中,实现不会尝试规范化资源名称。这意味着在这些版本中,classLoader.getResourceAsStream("/resource.txt")可能不会产生与事件相同的结果,classLoader.getResourceAsStream("resource.txt")尽管它应该(因为 Javadoc 指定)。[源代码]

但是在版本 8 中,资源名称被规范化以保证资源名称的绝对版本是使用的那个。因此,在 Tomcat 8 中,上述两个调用应该总是返回相同的结果。[源代码]

因此,在使用 Tomcat 8 之前的版本时,您必须格外小心ClassLoader.getResourceAsStream()Class.getResourceAsStream()并且您还必须记住class.getResourceAsStream("/resource.txt")实际调用classLoader.getResourceAsStream("resource.txt")(前导/被剥离)。

于 2009-03-24T05:52:21.640 回答
21

用于MyClass.class.getClassLoader().getResourceAsStream(path)加载与您的代码关联的资源。MyClass.class.getResourceAsStream(path)用作快捷方式,并用于打包在您的类包中的资源。

用于Thread.currentThread().getContextClassLoader().getResourceAsStream(path)获取属于客户端代码一部分的资源,而不是与调用代码紧密绑定。你应该小心这一点,因为线程上下文类加载器可能指向任何东西。

于 2009-03-24T11:57:39.330 回答
6

普通旧 Java 和普通旧 Java 7 上的普通旧 Java 没有其他依赖关系证明了差异......

我放入file.txtc:\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); 
  }
}
于 2015-07-09T17:13:36.563 回答
4

这里的所有这些答案,以及这个问题中的答案,都表明加载绝对 URL,如“/foo/bar.properties”,由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:我也发过这里

于 2013-11-19T11:02:54.773 回答
2

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

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

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

于 2018-03-20T15:03:51.520 回答
-4

它有效,试试这个:

InputStream in_s1 =   TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml");
于 2014-07-02T08:21:19.133 回答