小瓜牛漫谈 — 获取资源文件

 

在开发 WEB 运用的时候, 我常常忍受不了看到在 src 根目录底下放一堆配置文件, 在 WEB-INF 下又放一堆配置文件,

在某个比较隐藏的地方又存放了一些个配置文件, 这样总感觉很凌乱, 不方便也不好管理。

我更加倾向于使用 Maven 式的风格, 尽可能的通过 Source Folder 或 package 来管理项目的配置文件。

例如:

         或者              

其中, 资源文件放在 resources 根目录底下与放在 src 根目录底下是等效的, 因为在 Web Project 里面,

凡是 Source Folder 里面的东西最终都会编译到本地目录的 WebRoot/WEB-INF/classes 底下。

[ java 文件编译成了 .class 字节码文件存在于 classes, 非 java 文件则是直接拷贝搬过去。]

[ 如果是 Java Project, 则存在于项目所在的本地目录的 bin 目录底下, 实际上它们都是项目的类搜索路径。 ]

另外, 放在 package 里面的资源文件, 同样也会被编译(非 java 文件直接拷贝)到 classes 中, 存在于的目录与包名相对应。

 

由于资源文件放在 resources 与放在 src 底下效果是一致的, 所以接下主要是谈谈资源文件放在 package 下的情况。

以上面贴出来的右边的图为例, 资源文件放在 package 里面, 有时候常常需要自己去读取配置文件, 本人常用的手段有:

 

1> 通过 Class 类的 getResourceAsStream(String name) 方法来构造 InputStream。其中, name 的写法有两种: 绝对路径和相对路径。

 

1.1> 绝对路径:

1 public void app() throws IOException {
2     InputStream in = getClass().getResourceAsStream("/min/snail/resources/config.properties");
3     System.out.println(in.available()); // 字节数
4 }

绝对路径的写法是以 '/' 开头: /modified_package_name/name

modified_package_name 指的是修正后的包名, 简单的理解就是包名, name 是资源文件的名称(包括后缀名)。

[ 包名中的 '.' 分隔符在转换成路径来使用的时候, 通通需要将 '.' 改写成 '/' 或 '\\', 以下说的包名皆是这个意思。 ]

 

1.2> 相对路径:

1 public void app() throws IOException {
2     InputStream in = getClass().getResourceAsStream("./resources/config.properties");
3     System.out.println(in.available()); // 字节数
4 }

其中, app() 方法是写在 min.snail.Application 类里面。

'.' 代表的是当前 Class 对象的包名(以绝对路径形式), 在示例中相当于 /min/snail, 然后拼上后面的 resources/config.properties 就能找到资源文件。

也可以将 '.' 省略, 相对路径直接写成:

1 public void app() throws IOException {
2     InputStream in = getClass().getResourceAsStream("resources/config.properties");
3     System.out.println(in.available()); // 字节数
4 }

 

1.3> 假设 app() 方法不是写在 min.snail.Application 类, 而是写在 min.snail.copy.Application 类里面, 那么相对路径是:

1 public void app() throws IOException {
2     InputStream in = getClass().getResourceAsStream("./../resources/config.properties");
3     System.out.println(in.available());
4 }

根据 1.2 的分析, 这里的 '.' 表示的是: /min/snail/copy

'..' 相信大家都知道是什么意思, 就是返回到上一级目录, 当前目录是 /min/snail/copy, 那么上一级目录就是 /min/snail

再拼上后面的 /resources/config.properties 就是: /min/snail/resources/config.properties

或者直接写成:

1 public void app() throws IOException {
2     InputStream in = getClass().getResourceAsStream("../resources/config.properties");
3     System.out.println(in.available());
4 }

 

通过 Class 类的 getResourceAsStream(String name) 局限性比较大, 因为只能利用它来构造输入流, 如果想构造输出流, 那么这种方法就显得无能为力了。

 

2> 通过 FileInputStream(String name) 来构造 InputStream。

FileInputStream(String name) 在底层其实是通过 FileInputStream(File file) 构造方法来实现的, 因此会去调 new File(String pathname)。

首先是要知道如何去写 name 的值, 为解决这一问题, 下面是借助 File 类来帮助理解:

示例一:

1 public void app() {
2     File file = new File("");
3     System.out.println(file.exists());  //false
4     System.out.println(file.isFile());  //false
5     System.out.println(file.isDirectory()); //false
6     System.out.println(file.getAbsolutePath()); //F:\Workspace\X64\MyEclipse8.6\min-snail
7 }

示例二:

1 public void app() {
2     File file = new File(".");
3     System.out.println(file.exists());  //true
4     System.out.println(file.isFile());  //false
5     System.out.println(file.isDirectory()); //true
6     System.out.println(file.getAbsolutePath()); //F:\Workspace\X64\MyEclipse8.6\min-snail\.
7 }

示例一在构造 File 对象的时候传的是空串, 因此打印 file 不存在, file 不是一个文件, 也不是一个目录,

但此时 file 取得的绝对路径是项目所在磁盘的本地目录的路径;

示例二中, 结合示例一, 空串能取得项目所在本地磁盘的绝对路径, '.' 代表的是当前目录, 因此打印输出 file 存在,  

file 不是一个文件而是一个目录, file 取得的绝对路径是项目所在磁盘的本地目录的路径后面加了个 '.', 这里的 '.' 对路径是

没有影响的, 它代表的是它前面的那段串所构成的路径。

File(String pathname) 构造方法在底层是借助 native 方法来实现的, 我追踪不到源码, 因此,

以上关于 File 构造方法中的 '.' 的理解纯属个人看法, 如果有说的不对的地方, 欢迎广大网友指出。 ]

 

2.1> 从上面可以看出, 空串 "" 和 "." 取得的绝对路径都是项目的根目录所在的路径, 因此, 如何构造 FileInputStream(String name) 就有招可支了:

1 public void app() throws IOException {
2     InputStream in = new FileInputStream("./src/min/snail/resources/config.properties");
3     System.out.println(in.available()); // 字节数
4 }

因为 config.properties 文件就是存放在项目所在目录的 src/min/snail/resources/ 下, 而 '.' 能取到项目根目录的绝对路径。

也可以直接写成:

1 public void app() throws IOException {
2     InputStream in = new FileInputStream("src/min/snail/resources/config.properties");
3     System.out.println(in.available()); // 字节数
4 }

因为空串也能取得项目根目录的绝对路径, 我是这么理解的, 如果有说的不对的地方, 同样, 欢迎广大网友指出。

需要注意的是, 不能以 '/' 开头, 例如:

new FileInputStream("/src/min/snail/resources/config.properties");

new FileInputStream("/./src/min/snail/resources/config.properties");

上面的两种写法是错误的, 运行时程序会抛出 java.io.FileNotFoundException。

因为 FileInputStream(String name), 底层会去调 new File(name), 而 File("/") 得到的绝对路径是系统盘的根目录:

1 public void app() {
2     
3     File file = new File("/");
4     System.out.println(file.getAbsolutePath()); //F:\
5     
6     File file2 = new File("/src/min/snail/resources/config.properties");
7     System.out.println(file2.getAbsolutePath()); //F:\src\min\snail\resources\config.properties
8 }

 

3> 通过 ClassLoader.getSystemResource(String name) 来获取资源文件的路径。

ClassLoader.getSystemResource(String name) 返回的是一个 URL 对象, 接着可以通过 URL 类的 getPath() 方法来获取指定的 name 的绝对路径。

 

3.1> 先来看 ClassLoader.getSystemResource("") 构造出来的路径:

1 public void app() {
2     String path = ClassLoader.getSystemResource("").getPath();
3     System.out.println(path); // /F:/Workspace/X64/MyEclipse8.6/min-snail/WebRoot/WEB-INF/classes/
4 }

从打印结果可以看出, 空串 "" 获取的是项目的 classes 目录, 也就是项目的类搜索路径, 上面已经说到, package 里面的东西会被编译到 classes 中,

因此可以这样来找到资源文件路径:

1 public void app() {
2     String path = ClassLoader.getSystemResource("min/snail/resources/config.properties").getPath();
3     System.out.println(path); ///F:/Workspace/X64/MyEclipse8.6/min-snail/WebRoot/WEB-INF/classes/min/snail/resources/config.properties
4 }

另外, ClassLoader.getSystemResource("") 与 ClassLoader.getSystemResource(".")、

ClassLoader.getSystemResource("min/snail/resources/config.properties").getPath() 与

ClassLoader.getSystemResource("./min/snail/resources/config.properties").getPath()

的异同与上面所述是相类似的, 这里不再赘述。

同样需要注意的是, 不能以 '/' 开头, 以 '/' 开头表明是绝对路径的写法, java 会直接根据 '/' 后面的字符串来寻找路径, 如写成:

ClassLoader.getSystemResource("/min/snail/resources/config.properties").getPath()

ClassLoader.getSystemResource("/./min/snail/resources/config.properties").getPath()

程序在运行时都会抛出 java.lang.NullPointerException 异常。

 

正确示例:

1 public void app() throws IOException {
2     String path = ClassLoader.getSystemResource("min/snail/resources/config.properties").getPath();
3     InputStream in = new FileInputStream(path);
4     System.out.println(in.available()); // 字节数
5 }

注意: ClassLoader.getSystemResource(name) 这种方式不允许路径中含有空格或中文, 否则同样抛出 java.lang.NullPointerException 异常。

 

 

posted on 2013-04-28 12:10  小瓜牛  阅读(1535)  评论(1编辑  收藏  举报

博客链接: http://www.blogjava.net/fancydeepin