getResourceAsStream()与FileInputStream


Answers:


256

java.io.File和配偶的行为在本地磁盘文件系统上。问题的根本原因是其中的相对路径java.io取决于当前工作目录。即从中启动JVM(在您的情况下为:Web服务器的目录)的目录。例如,这可能是C:\Tomcat\bin或完全不同的东西,但是却并非 如此,C:\Tomcat\webapps\contextname或者您期望的是什么。在正常的Ec​​lipse项目中,该值为C:\Eclipse\workspace\projectname。您可以通过以下方式了解当前工作目录:

System.out.println(new File(".").getAbsolutePath());

但是,工作目录绝不是以编程方式可控制的。您确实应该更喜欢在API中使用绝对路径,File而不是相对路径。例如C:\full\path\to\file.ext

您不想硬编码或猜测Java(Web)应用程序中的绝对路径。那只是可移植性的麻烦(即它在系统X中运行,而不在系统Y中运行)。通常的做法是将此类资源放置在类路径中,或将其完整路径添加到类路径中(在像Eclipse这样的IDE中,分别是src文件夹和“构建路径”)。这样,您可以借助ClassLoaderby ClassLoader#getResource()或抓住它们ClassLoader#getResourceAsStream()。巧合的是,它能够相对于类路径的“根”定位文件。在Web应用程序(或使用多个类加载器的任何其他应用程序)中,建议为此使用ClassLoader返回的as Thread.currentThread().getContextClassLoader(),以便您也可以在webapp上下文之外查找。

webapps中的另一种替代方法是ServletContext#getResource()ServletContext#getResourceAsStream()。它能够访问位于webwebapp项目的/WEB-INF公用文件夹中的文件,包括该文件夹。该ServletContext是由继承的Servlet可用getServletContext()的方法,你可以把它原样。

也可以看看:



27

getResourceAsStream 是针对网络应用的正确方法(如您所知)。

原因是,如果将Web应用程序打包在WAR中,则无法从文件系统读取数据。这是打包Web应用程序的正确方法。这种方式可移植,因为您不依赖于绝对文件路径或应用服务器的安装位置。


3
+1-尽管“无法工作”太强。(可以使从文件系统中进行读取工作,但是可移植地进行读取是一个棘手的工作……并且还有很多代码,尤其是如果资源位于JAR中。)
Stephen C 2010年

1
达菲,很好的答案,你解释了我的错误,但是BalusC讲了很多细节-我认为他的答案对想了解内部细节的人也很有帮助。希望你不介意我改变他的公认答案!
Vivin Paliath '02

@Stephen-我认为“无法正常工作”不太强。即使只是简单地部署到具有不同路径的两台不同服务器上的应用程序,也会破坏它。关键是您需要使WAR尽可能独立。您的观点是正确的,但我会坚持我的措辞。
duffymo'2

14

FileInputStream将从Java进程的工作目录中加载相对于您传递给构造函数的文件路径。通常在Web容器中,这类似于bin文件夹。

getResourceAsStream()将从应用程序的classpath加载相对的文件路径。


12

FileInputStream类直接与底层的文件系统。如果相关文件不在此处,则它将无法打开。该getResourceAsStream()方法的工作原理有所不同。它尝试使用ClassLoader被调用的类的来查找和加载资源。这样,它就可以查找嵌入到jar文件中的资源。


好吧,jar中的文件实际上仍然“存在”于文件系统中,只是包含在其他文件中
matt b 2010年

1
好,是的,当然。但是,除非您的应用程序碰巧知道jar文件格式及其含义,否则它们通常不被视为文件系统中的独立实体。并且在Java中,适当的人ClassLoader可能具有此知识,而普通人FileInputStream当然没有。
德克2010年

7

classname.getResourceAsStream()通过classname的类加载器加载文件。如果该类来自jar文件,则将从那里加载资源。

FileInputStream用于从文件系统读取文件。


0

我在这里通过将这两种用法标记为File Read(java.io)和Resource Read(ClassLoader.getResourceAsStream())来分开使用。

文件读取-1 .在本地文件系统上工作。2.尝试将当前JVM启动目录中请求的文件作为根目录定位。3.在预定位置使用文件进行处理时,如/ dev / files或C:\ Data,这是非常好的选择。

资源读取-1 .在类路径上工作。2.尝试在当前或父类加载器的类路径中找到文件/资源​​。3.尝试从打包文件(如war或jar)中加载文件时,非常理想。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.