java文件读取的路径问题解惑和最佳实践,让你远离FileNotFoundException
2014-07-02 23:22
501 查看
使用java读取jar或war下的配置文件,是开发者经常需要处理的事情,大家是不是经常遇到FileNotFoundException呢?java读取文件的方式也有很多,比如new File(),Class.getResource(),ClassLoader.getResource(),这些方式的差别是什么呢?开源框架struts2的ClassLoaderUtils和Spring提供ClassPathResource,都提供了对资源读取进行封装的工具类,你是否了解他们的实现原理呢?本文结合网上的一些博客和自己的理解,和大家一起讨论下java的文件读取问题。
在eclipse中运行上面的程序,发现2种方式都是能够正确读取文件的,不会抛FileNotFoundException。
使用绝对路径,虽然定位很清晰,但是不灵活。比如你将上面的工程放到D盘下,就必须要修改绝对路径路径,这显然很不方便。使用相对路径则跟工程所在的硬盘路径无关,直接导入eclipse中运行,就能够正确读取文件内容。而且实际情况是,很多时候我们并不知道文件的绝对路径,这会因为部署环境的不同而不同。比如将***好的war放到tomcat或jboss容器下运行,很显然绝对路径是不同的,而我们的代码事先并不知道。
那么使用相对路径呢?很遗憾,也同样存在很多问题。File是java.io包的基础类,java.io 包中的类总是根据当前用户目录来分析相对路径名。也就是说以下2种方式是等价的,
对于tomcat/jboss容器,user.dir是%home/bin%/目录,因为这个目录就是我们启动web容器的地方。也就是说,user.dir也是可变的,不固定的。显然使用这种方式跟绝对路径没有什么本质差别,都是不推荐的。顺便提一下,我们在eclipse中运行程序的时候,eclipse会将user.dir的值设置为工程的根目录,在我们的例子中,user.dir是c:/workspace/path_project/
可以得出结论:使用java.io.File读取文件,无论是相对路径,还是绝对路径都不是好的做法,能不使用就不要使用。
Class.getResource()有2种方式,绝对路径和相对路径。绝对路径以/开头,从classpath或jar包根目录下开始搜索;
相对路径是相对当前class所在的目录,允许使用..或.来定位文件。ClassLoader.getResource()只能使用绝对路径,而且不用以/开头。
这两种方式读取资源文件,不会依赖于user.dir,也不会依赖于具体部署的环境,是推荐的做法。
用相对路径和绝对路径都可以吗?
***b.jar,并将它加入到eclipse工程的build path下,如下图
使用相对路径或绝对路径都能读取本jar或其他jar中的资源文件。但区别是,读取本jar包中的文件支持..这种写法,但是不能通过..读取其他jar下的文件。
1.使用new File()的问题
File是java.io包下的基础类,代表硬盘上的一个文件或者目录,我们可以使用绝对路径来构造,也可以使用相对路径来构造。public class TestFile { public static void main(String[] args) throws Exception { File absoluteFile = new File("c:/workspace/path_project/demo.txt"); File relativeFile = new File("demo.txt"); showFileContent(absoluteFile); showFileContent(relativeFile); } public static void showFileContent(File file) throws Exception { BufferedReader br = new BufferedReader(new FileReader(file)); StringBuilder contentHolder = new StringBuilder(); String lineContent = null; while ((lineContent = br.readLine()) != null) { contentHolder.append(lineContent); } br.close(); System.out.println("content=" + contentHolder); } }工程在硬盘和eclipse的目录结构如下:
在eclipse中运行上面的程序,发现2种方式都是能够正确读取文件的,不会抛FileNotFoundException。
使用绝对路径,虽然定位很清晰,但是不灵活。比如你将上面的工程放到D盘下,就必须要修改绝对路径路径,这显然很不方便。使用相对路径则跟工程所在的硬盘路径无关,直接导入eclipse中运行,就能够正确读取文件内容。而且实际情况是,很多时候我们并不知道文件的绝对路径,这会因为部署环境的不同而不同。比如将***好的war放到tomcat或jboss容器下运行,很显然绝对路径是不同的,而我们的代码事先并不知道。
那么使用相对路径呢?很遗憾,也同样存在很多问题。File是java.io包的基础类,java.io 包中的类总是根据当前用户目录来分析相对路径名。也就是说以下2种方式是等价的,
File file1 = new File("demo.txt"); String asbPath = System.getProperty("user.dir") + "/demo.txt"; File file2 = new File(asbPath);也就是说相对路径是否好使,取决于user.dir的值。系统属性 user.dir是JVM启动的时候设置的,通常是 Java 虚拟机的调用目录,即执行java命令所在的目录。
对于tomcat/jboss容器,user.dir是%home/bin%/目录,因为这个目录就是我们启动web容器的地方。也就是说,user.dir也是可变的,不固定的。显然使用这种方式跟绝对路径没有什么本质差别,都是不推荐的。顺便提一下,我们在eclipse中运行程序的时候,eclipse会将user.dir的值设置为工程的根目录,在我们的例子中,user.dir是c:/workspace/path_project/
可以得出结论:使用java.io.File读取文件,无论是相对路径,还是绝对路径都不是好的做法,能不使用就不要使用。
2.使用Class.getResource()或ClassLoader.getResource()
这2个方法用来读取jar包中或者classpath下的资源文件。以下方式都能够正确的定位文件TestClass.class.getResource("test.txt"); TestClass.class.getResource("/net/aty/test.txt"); TestClass.class.getClassLoader().getResource("net/aty/test.txt");
Class.getResource()有2种方式,绝对路径和相对路径。绝对路径以/开头,从classpath或jar包根目录下开始搜索;
相对路径是相对当前class所在的目录,允许使用..或.来定位文件。ClassLoader.getResource()只能使用绝对路径,而且不用以/开头。
这两种方式读取资源文件,不会依赖于user.dir,也不会依赖于具体部署的环境,是推荐的做法。
3.使用Class或ClassLoader.getResource()的相对路径和绝对路径问题
无论是相对路径还是绝对路径,都是推荐的做法。考虑下这样的场景,如果a.jar中的类,需要读取b.jar中的资源文件怎么实现呢?用相对路径和绝对路径都可以吗?
***b.jar,并将它加入到eclipse工程的build path下,如下图
package net.aty; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; public class TestClass { public static void main(String[] args) throws Exception { // 使用相对路径,正常读取b.jar中的文件 showContent(TestClass.class.getResource("b.txt")); // 使用相对路径,正常读取b.jar中的文件 showContent(TestClass.class.getResource("test/c.txt")); // 使用绝对对路径,正常读取b.jar中的文件 showContent(TestClass.class.getResource("/net/a.txt")); // 使用绝对对路径,正常读取b.jar中的文件 showContent(TestClass.class.getClassLoader().getResource("net/aty/test/c.txt")); // 使用相对路径,正常读取本jar中的same.txt showContent(TestClass.class.getResource("../same.txt")); // 错误 showContent(TestClass.class.getResource("../a.txt")); } public static void showContent(URL url) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader( url.openStream())); StringBuilder contentHolder = new StringBuilder(); String lineContent = null; while ((lineContent = br.readLine()) != null) { contentHolder.append(lineContent); } br.close(); System.out.println("content=" + contentHolder); } }可以得出结论:
使用相对路径或绝对路径都能读取本jar或其他jar中的资源文件。但区别是,读取本jar包中的文件支持..这种写法,但是不能通过..读取其他jar下的文件。
4.spring框架的ClassPathResource实现
/** * This implementation opens an InputStream for the given class path resource. * @see java.lang.ClassLoader#getResourceAsStream(String) * @see java.lang.Class#getResourceAsStream(String) */ public InputStream getInputStream() throws IOException { InputStream is; if (this.clazz != null) { is = this.clazz.getResourceAsStream(this.path); } else { is = this.classLoader.getResourceAsStream(this.path); } if (is == null) { throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist"); } return is; }可以看出spring提供的ClassPathResource,底层使用的就是Class.getResource或ClassLoader.getResource()。spring提供的读取文件API功能,自然是与JDK一致。
相关文章推荐
- 文件路径正确,报java.io.FileNotFoundException异常
- 关于IO流在复制文件时出现java.io.FileNotFoundException: D:\xxx (拒绝访问。) 拒绝访问的问题
- 新手迷惑:复制文件路径报错java.io.FileNotFoundException
- 文件路径正确,报java.io.FileNotFoundException异常的原因及解决办法
- java.io.FileNotFoundException问题,说是db.properties文件找不到,但是在webapps里存在的
- 写文件流报:java.io.FileNotFoundException.....\img (拒绝访问。)的问题真正病根
- java.io.FileNotFoundException: 下载项目路径下的文件
- springboot打的jar包中的文件读取问题。fileNotFoundException
- java.io.FileNotFoundException问题,说是db.properties文件找
- 获取文件上传路径报错:java.io.FileNotFoundException: (文件名、目录名或卷标语法不正确。)
- 写文件流报:java.io.FileNotFoundException.....\img (拒绝访问。)的问题真正病根
- 新手迷惑:复制文件路径报错java.io.FileNotFoundException
- 读取属性文件时提示FileNotFound或路径查找不到时遇到的问题备忘
- windows下获取文件上传路径报错:java.io.FileNotFoundException: (文件名、目录名或卷标语法不正确。)
- spring MVC 上传多文件问题:java.lang.NoClassDefFoundError: org/apache/commons/fileupload/FileItemFactory java.lang.ClassNotFoundException: org.apache.commons.fileupload.FileItemFactory
- Java项目读取配置文件时,FileNotFoundException 系统找不到指定的文件,System.getProperty("user.dir")的理解
- java 关于FileNotFoundException: D:\xxx\yyy (拒绝访问。)问题解析
- Java读取TXT编译报错FileNotFoundException
- Android下载文件提示文件不存在。。。 java.io.FileNotFoundException
- junit测试时找不到资源路径java.io.FileNotFoundException: class path resource [config/EBSConfig.xml] cannot be o