有什么区别:
1
| InputStream is = this. getClass(). getClassLoader(). getResourceAsStream(fileName ) |
和
1
| InputStream is = Thread. currentThread(). getContextClassLoader(). getResourceAsStream(fileName ) |
和
1
| InputStream is = this. getClass(). getResourceAsStream(fileName ) |
什么时候每个人都比其他人更适合使用?
我要读取的文件作为我的类在类路径中读取该文件。我的类和文件在同一个JAR中,打包在一个EAR文件中,并部署在WebSphere6.1中。
对于您传递的fileName的解释方式有细微的差异。基本上,您有两种不同的方法:ClassLoader.getResourceAsStream()和Class.getResourceAsStream()。这两种方法将不同地定位资源。
在Class.getResourceAsStream(path)中,路径被解释为调用它的类的包的本地路径。例如,调用String.getResourceAsStream("myfile.txt")将在类路径的以下位置查找文件:"java/lang/myfile.txt"。如果您的路径以/开头,那么它将被视为绝对路径,并将从类路径的根开始搜索。因此,调用String.getResourceAsStream("/myfile.txt")将查看类路径./myfile.txt中的以下位置。
ClassLoader.getResourceAsStream(path)将所有路径视为绝对路径。因此,调用String.getClassLoader().getResourceAsStream("myfile.txt")和String.getClassLoader().getResourceAsStream("/myfile.txt")都将在类路径中的以下位置查找文件:./myfile.txt。
每当我在本文中提到一个位置时,它可能是文件系统本身中的一个位置,也可能是相应JAR文件中的一个位置,这取决于从中加载资源的类和/或类加载器。
在您的例子中,您是从应用服务器加载类的,因此您应该使用Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName),而不是this.getClass().getClassLoader().getResourceAsStream(fileName)。this.getClass().getResourceAsStream()也将起作用。
阅读本文了解有关该特定问题的更多详细信息。
Tomcat 7及以下用户的警告
这个问题的答案之一是,我的解释对Tomcat7来说似乎是不正确的。我试着四处看看为什么会这样。
因此,我研究了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中,资源名被规范化,以确保资源名的绝对版本是所使用的版本。因此,在Tomcat8中,上面描述的两个调用应该始终返回相同的结果。[源代码]
因此,在8之前的Tomcat版本上使用ClassLoader.getResourceAsStream()或Class.getResourceAsStream()时必须格外小心。您还必须记住,class.getResourceAsStream("/resource.txt")实际上称为classLoader.getResourceAsStream("resource.txt")(前面的/)。
- 我很肯定,getClass().getResourceAsStream("/myfile.txt")的行为与getClassLoader().getResourceAsStream("/myfile.txt")的行为不同。
- @他们的行为没有什么不同。实际上,class.getresourceasstream(string)的javadoc中说:"这个方法委托给这个对象的类加载器。",然后给出了一系列规则,说明如何在委托给类加载器之前将相对路径转换为绝对路径。
- @领主们看看实际的来源。class.getResourceAsstream如果提供绝对路径,则去掉前导正斜杠。
- @briangordon:这使得它的行为与classloader.getResourceAsstream()完全相同,因为后者将所有路径解释为绝对路径,不管它们是否以前导斜杠开头。因此,只要您的路径是绝对的,这两个方法的行为都是相同的。如果你的路径是相对的,那么行为是不同的。
使用MyClass.class.getClassLoader().getResourceAsStream(path)加载与代码相关联的资源。将MyClass.class.getResourceAsStream(path)用作快捷方式,并用于类包中打包的资源。
使用Thread.currentThread().getContextClassLoader().getResourceAsStream(path)获取属于客户机代码的资源,而不是与调用代码严格绑定的资源。您应该小心这一点,因为线程上下文类加载器可能指向任何东西。
普通旧Java 7上的纯Java,没有其他依赖性证明了差异。
我把file.txt放在c:\temp\中,把c:\temp\放在类路径上。
只有一种情况是两个调用之间存在差异。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 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);
}
} |
- 非常感谢,因为我只工作过'j.class.getresourceasstream("file.txt")'
这里的所有这些答案以及这个问题的答案都表明加载绝对URL,比如"foo/bar.properties"被class.getResourceAsStream(String)和class.getClassLoader().getResourceAsStream(String)处理相同。但情况并非如此,至少在我的Tomcat配置/版本(目前为7.0.40)中没有。
1 2
| MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work! |
对不起,我没有令人满意的解释,但我猜Tomcat会用下流的技巧和他在课堂上的黑色魔法,并造成不同。我过去一直使用class.getResourceAsStream(String),没有任何问题。
附:我也把这个贴在这里了
- 也许Tomcat决定不遵守规范,并且不将通过ClassLoader.getResourceAsStream()的所有路径都视为绝对路径?这是合理的,因为正如上面的一些评论中所提到的,Class.getResourceAsStream实际上调用getClassLoader().getResourceAsstream`但去掉了任何前导斜杠。
- 在检查Java SE的源代码之后,我认为我的答案是:EDCOX1×4和EDCOX1 2都最终调用EDCOX1×6,这是一个默认实现为空的受保护方法,但是JavaDoc显式声明"类加载器实现应该重写该方法来指定在哪里查找资源"。我怀疑Tomcat对这个特定方法的实现可能有缺陷。
- 我还比较了Tomcat 7和Tomcat 8中WebAppClassLoader.findResource(String name)的实现,发现两者之间有一个关键区别。Tomcat8通过添加一个前导的/显式规范化资源名(如果不包含任何),这使得所有名称都是绝对的。Tomcat 7没有,这显然是Tomcat 7的一个缺陷。
- 我在回答中加了一段。
在尝试了一些加载文件但没有成功的方法之后,我记得我可以使用FileInputStream,这非常有效。
这是将文件读取到InputStream中的另一种方法,它从当前运行的文件夹中读取文件。
- 它不是文件,而是资源。答案不正确。
- @EJP最终得到了这样的答案,寻找加载文件的方法,而不知道文件和资源之间的区别。我不会删除我的答案,因为它可以帮助其他人。
有效,试试这个:
1
| InputStream in_s1 = TopBrandData. class. getResourceAsStream("/assets/TopBrands.xml"); |