项目编译后资源文件夹分析
一般的Java项目目录下有两部分静态资源文件夹:
- java 文件夹。
- resources 文件夹。
项目编译时期会将这两个文件夹下的文件分别按照包层级(文件夹层级)和文件夹层级关系放到target/classes文件夹下
通过这些分析可以认识到:获取包目录下的资源文件就是包路径加上文件名,获取resources下的资源文件直接使用文件名,如果resources下有文件夹毫无疑问需要加上文件夹名。
获取资源方式
1. 通过当前线程的上下文类加载器或者当前类的类加载器获取资源
Thread.currentThread().getContextClassLoader().getResourceAsStream("com/freesky/io/ch.properties");
ResourcesTest.class.getClassLoader().getResourceAsStream("com/freesky/io/ch.properties");
这种方式传入的path就是文件的包路径,前面不要加“/”因为Java不会对这个“/”做任何处理。
2. 通过Class.getResourceAsStream(String name)方法获取资源
ResourcesTest.class.getResourceAsStream("/com/freesky/io/ch.properties")
注意,这种方式前面必须加“/”,是什么原因呢?跟代码看看
public InputStream getResourceAsStream(String name) {
//该方法对传入的路径进行了处理
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
代码:name = resolveName(name);对传入的路径进行了处理
private String resolveName(String name) {
if (name == null) {
return name;
}
//判断是否是以“/”开头
if (!name.startsWith("/")) {
//不是以“/”开头逻辑处理
Class<?> c = this;
while (c.isArray()) {
c = c.getComponentType();
}
//获取当前类Class的的名称
//com.freesky.io.ResourcesTest
String baseName = c.getName();
//下面的逻辑就是获取该类的包路径,拼加在name上
//结果就是这样:com/freesky/io/com/freesky/io/ch.properties
//这个路径根本就不存在
int index = baseName.lastIndexOf('.');
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/')
+"/"+name;
}
} else {
//如果是以“/”开头就直接去掉“/”
name = name.substring(1);
}
return name;
}
maven或者gradle项目下用这种方式获取的文件流为空
通过上图可以发现编译后的资源文件夹下找不见需要获取的文件“ch.properties”,这是因为maven项目将包路径不看做资源文件夹,需要加上以下配置将包路径设置为资源文件夹,并可以指定文件格式:
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
再次编译:
gradle的配置如下:
sourceSets {
main {
//指定资源文件夹
resources.srcDirs = ['src/main/resources', 'src/main/java']
}
}