我正在尝试在webapp中加载文件,当我使用FileNotFound
时,我收到FileInputStream
例外。但是,使用相同的路径,我能够在getResourceAsStream()
时加载文件。
这两种方法之间有什么区别,为什么一种方法有效而另一方方法无效?
答案 0 :(得分:253)
java.io.File
和consorts作用于本地磁盘文件系统。问题的根本原因是java.io
中的相对路径依赖于当前工作目录。即启动JVM(在您的情况下:Web服务器的一个)的目录。例如,这可能是C:\Tomcat\bin
或完全不同的东西,但因此不是 C:\Tomcat\webapps\contextname
或者您期望的那样。在普通的Eclipse项目中,这将是C:\Eclipse\workspace\projectname
。您可以通过以下方式了解当前的工作目录:
System.out.println(new File(".").getAbsolutePath());
但是,工作目录绝不能以编程方式控制。您应该更喜欢在File
API中使用绝对路径而不是相对路径。例如。 C:\full\path\to\file.ext
。
您不希望硬编码或猜测Java(Web)应用程序中的绝对路径。这只是可移植性问题(即它在系统X中运行,但在系统Y中不运行)。通常的做法是将这些资源放在类路径中,或者将其完整路径添加到类路径中(在像Eclipse这样的src
文件夹和“构建路径”的IDE中分别)。这样,您可以在ClassLoader#getResource()
或ClassLoader#getResourceAsStream()
的ClassLoader
的帮助下抓住它们。它可以找到相对于类路径的“根”的文件,因为巧合的想法。在webapplications(或任何其他使用多个类加载器的应用程序)中,建议使用ClassLoader
返回的Thread.currentThread().getContextClassLoader()
,以便您可以在webapp上下文之外查看。
webapps中的另一个替代方案是ServletContext#getResource()
及其对应的ServletContext#getResourceAsStream()
。它能够访问位于webapp项目的公共web
文件夹中的文件,包括/WEB-INF
文件夹。 ServletContext
可以通过继承的getServletContext()
方法在servlet中使用,您可以按原样调用它。
答案 1 :(得分:26)
getResourceAsStream
是为网络应用做的正确方法(正如您已经了解的那样)。
原因是如果您将Web应用程序打包在WAR中,则无法从文件系统读取。这是打包Web应用程序的正确方法。它是可移植的,因为您不依赖于绝对文件路径或安装应用服务器的位置。
答案 2 :(得分:13)
FileInputStream将从Java进程的工作目录加载传递给构造函数的文件路径。通常在Web容器中,这类似于bin
文件夹。
getResourceAsStream()
将加载相对from your application's classpath的文件路径。
答案 3 :(得分:12)
FileInputStream
类直接与底层文件系统一起工作。如果有问题的文件没有在那里存在,它将无法打开它。 getResourceAsStream()
方法的工作方式不同。它尝试使用调用它的类的ClassLoader
来定位和加载资源。这使它能够找到嵌入jar
文件中的资源。
答案 4 :(得分:6)
classname.getResourceAsStream()通过classname的类加载器加载文件。如果该类来自jar文件,那么将从中加载资源。
FileInputStream用于从文件系统中读取文件。
答案 5 :(得分:0)
我在这里通过将这两种用法标记为File Read(java.io)和Resource Read(ClassLoader.getResourceAsStream())来分开使用。
文件读取- 1.在本地文件系统上工作。 2.尝试以root用户身份找到当前JVM启动目录中请求的文件 3.使用文件在预定位置(例如/ dev / files或C:\ Data)进行处理时,非常理想。
资源阅读- 1.在课程路径上工作 2.尝试在当前或父类加载器的类路径中找到文件/资源。 3.尝试从打包文件(如war或jar)中加载文件时非常理想。