在开发 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> 绝对路径:
app() throws IOException {2InputStream in = getClass().getResourceAsStream(“/min/snail/resources/config.properties”);}
绝对路径的写法是以 ‘/’ 开头: /modified_package_name/name
modified_package_name 指的是修正后的包名, 简单的理解就是包名, name 是资源文件的名称(包括后缀名)。
[包名中的 ‘.’ 分隔符在转换成路径来使用的时候, 通通需要将 ‘.’改写成 ‘/’ 或 ‘\\’, 以下说的包名皆是这个意思。]
1.2> 相对路径:
app() throws IOException {2InputStream in = getClass().getResourceAsStream(“./resources/config.properties”);}
其中, app() 方法是写在 min.snail.Application 类里面。
‘.’ 代表的是当前 Class 对象的包名(以绝对路径形式), 在示例中相当于 /min/snail, 然后拼上后面的 resources/config.properties 就能找到资源文件。
也可以将 ‘.’ 省略, 相对路径直接写成:
app() throws IOException {2InputStream in = getClass().getResourceAsStream(“resources/config.properties”);}
1.3> 假设 app() 方法不是写在 min.snail.Application 类, 而是写在 min.snail.copy.Application 类里面, 那么相对路径是:
app() throws IOException {2InputStream 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
或者直接写成:
app() throws IOException {2InputStream 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 类来帮助理解:
示例一:
app() {2File file = new File(“”);System.out.println(file.isFile()); System.out.println(file.isDirectory()); System.out.println(file.getAbsolutePath()); }
示例二:
app() {2File file = new File(“.”);System.out.println(file.isFile()); System.out.println(file.isDirectory()); System.out.println(file.getAbsolutePath()); }
示例一在构造 File 对象的时候传的是空串, 因此打印 file 不存在, file 不是一个文件, 也不是一个目录,
但此时 file 取得的绝对路径是项目所在磁盘的本地目录的路径;
示例二中, 结合示例一, 空串能取得项目所在本地磁盘的绝对路径, ‘.’ 代表的是当前目录, 因此打印输出 file存在,
file 不是一个文件而是一个目录, file 取得的绝对路径是项目所在磁盘的本地目录的路径后面加了个 ‘.’, 这里的 ‘.’ 对路径是
没有影响的, 它代表的是它前面的那段串所构成的路径。
[File(String pathname) 构造方法在底层是借助 native 方法来实现的, 我追踪不到源码, 因此,
以上关于File 构造方法中的 ‘.’ 的理解纯属个人看法, 如果有说的不对的地方, 欢迎广大网友指出。]
2.1> 从上面可以看出, 空串 “” 和 “.” 取得的绝对路径都是项目的根目录所在的路径, 因此, 如何构造 FileInputStream(String name) 就有招可支了:
app() throws IOException {2InputStream in = new FileInputStream(“./src/min/snail/resources/config.properties”);}
因为 config.properties 文件就是存放在项目所在目录的 src/min/snail/resources/ 下, 而 ‘.’ 能取到项目根目录的绝对路径。
也可以直接写成:
app() throws IOException {2InputStream in = new FileInputStream(“src/min/snail/resources/config.properties”);}
因为空串也能取得项目根目录的绝对路径, 我是这么理解的, 如果有说的不对的地方, 同样, 欢迎广大网友指出。
需要注意的是, 不能以 ‘/’ 开头, 例如:
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(“/”) 得到的绝对路径是系统盘的根目录:
可以提高你的水平。(戏从对手来。