我试图将文件加载到Web应用程序中,FileNotFound
但使用时出现异常FileInputStream
。但是,使用相同的路径时,我能够加载文件getResourceAsStream()
。两种方法有什么区别,为什么一种方法有效而另一种无效?
我试图将文件加载到Web应用程序中,FileNotFound
但使用时出现异常FileInputStream
。但是,使用相同的路径时,我能够加载文件getResourceAsStream()
。两种方法有什么区别,为什么一种方法有效而另一种无效?
Answers:
在java.io.File
和配偶的行为在本地磁盘文件系统上。问题的根本原因是其中的相对路径java.io
取决于当前工作目录。即从中启动JVM(在您的情况下为:Web服务器的目录)的目录。例如,这可能是C:\Tomcat\bin
或完全不同的东西,但是却并非 如此,C:\Tomcat\webapps\contextname
或者您期望的是什么。在正常的Eclipse项目中,该值为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
文件夹和“构建路径”)。这样,您可以借助ClassLoader
by ClassLoader#getResource()
或抓住它们ClassLoader#getResourceAsStream()
。巧合的是,它能够相对于类路径的“根”定位文件。在Web应用程序(或使用多个类加载器的任何其他应用程序)中,建议为此使用ClassLoader
返回的as Thread.currentThread().getContextClassLoader()
,以便您也可以在webapp上下文之外查找。
webapps中的另一种替代方法是ServletContext#getResource()
和ServletContext#getResourceAsStream()
。它能够访问位于web
webapp项目的/WEB-INF
公用文件夹中的文件,包括该文件夹。该ServletContext
是由继承的Servlet可用getServletContext()
的方法,你可以把它原样。
getResourceAsStream
是针对网络应用的正确方法(如您所知)。
原因是,如果将Web应用程序打包在WAR中,则无法从文件系统读取数据。这是打包Web应用程序的正确方法。这种方式可移植,因为您不依赖于绝对文件路径或应用服务器的安装位置。
FileInputStream将从Java进程的工作目录中加载相对于您传递给构造函数的文件路径。通常在Web容器中,这类似于bin
文件夹。
getResourceAsStream()
将从应用程序的classpath加载相对的文件路径。
本FileInputStream
类直接与底层的文件系统。如果相关文件不在此处,则它将无法打开。该getResourceAsStream()
方法的工作原理有所不同。它尝试使用ClassLoader
被调用的类的来查找和加载资源。这样,它就可以查找嵌入到jar
文件中的资源。
jar
文件格式及其含义,否则它们通常不被视为文件系统中的独立实体。并且在Java中,适当的人ClassLoader
可能具有此知识,而普通人FileInputStream
当然没有。
classname.getResourceAsStream()通过classname的类加载器加载文件。如果该类来自jar文件,则将从那里加载资源。
FileInputStream用于从文件系统读取文件。
我在这里通过将这两种用法标记为File Read(java.io)和Resource Read(ClassLoader.getResourceAsStream())来分开使用。
文件读取-1 .在本地文件系统上工作。2.尝试将当前JVM启动目录中请求的文件作为根目录定位。3.在预定位置使用文件进行处理时,如/ dev / files或C:\ Data,这是非常好的选择。
资源读取-1 .在类路径上工作。2.尝试在当前或父类加载器的类路径中找到文件/资源。3.尝试从打包文件(如war或jar)中加载文件时,非常理想。