将文件加载为InputStream的不同方法

时间:2009-03-24 05:32:44

标签: java inputstream

有什么区别:

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

6 个答案:

答案 0 :(得分:277)

关于如何解释你传递的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文件中的位置,具体取决于你从中加载资源的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")实际调用{{} 1}}(前导classLoader.getResourceAsStream("resource.txt")被剥离)。

答案 1 :(得分:20)

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

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

答案 2 :(得分:5)

普通旧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); 
  }
}

答案 3 :(得分:3)

这里的所有答案以及this question中的答案都建议加载绝对网址,例如" /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:我也在here

上发布了这个帖子

答案 4 :(得分:0)

在尝试某些方法加载文件但没有成功之后,我记得我可以使用FileInputStream,这非常有效。

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

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

答案 5 :(得分:-3)

有效,试试这个:

InputStream in_s1 =   TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml");