首先,项目中文件分布情况如下,innerFile.txt位于test.test包下,innerInnerFile.txt位于test.test.inner包下,outterFile.txt位于包的根目录下,
那么,在App类里,如何根据相对路径、绝对路径获取innerFile.txt、innerInnerFile.txt和outterFile.txt呢?
class.getResource(name)
先来看一下Class.getResource(name)
方法,该方法接收一个表示文件路径的参数,返回一个URL对象,该URL对象表示的name指向的那个资源(文件)。这个方法是在类中根据name获取资源。其中,name可以是文件的相对路径(相对于该class类来说),也可以是绝对路径(绝对路径的话,根目录符号/
是代表项目路径而不是磁盘的根目录)。例如,如下两种根据路径获取文件的效果是一样的 :
App.class.getResource('innerFile.txt')
App.class.getResource('/test/test/innerFile.txt')
由于innerFile.txt和App类是在同一个包下,所以通过App.class和相对路径可以获取到App这个类的包下面的innerFile.txt文件。而当传入的是绝对路径/test/test/innerFile.txt
,getResource()方法是从项目的包的根目录开始解析路径的。所以这两种获取文件的效果是一样的。
classLoader.getResource(name)
该方法的作用与class.getResource(name)
的作用一样,接收一个表示路径的参数,返回一个URL对象,该URL对象表示name对应的资源(文件)。但是,与class.getResource(name)
不同的是,该方法只能接收一个相对路径,不能接收绝对路径如/xxx/xxx
。并且,接收的相对路径是相对于项目的包的根目录来说的。比如,如下两种获取文件的效果是一样的:
App.class.getResource('innerFile.txt')
App.class.getClassLoader().getResource('test/test/innerFile.txt')
classLoader.getResource('test/test/innerFile.txt')
是相对于项目的包的根目录来解析路径的,所以通过该路径能够获取到innerFile.txt,并且不能传入绝对路径,否则报错。
介绍完了这两种,那么应该能够根据这两种方法分别获取到innerInnerFile.txt文件和outterFile.txt文件吧?
class.getResource(name)与classLoader.getResource(name)的联系
如上所述,class.getResource(name)
能够接受相对路径和绝对路径,而classLoader.getResource(name)
只能接收相对路径,那么这两种方法的联系是什么呢?
通过查看class.getResource(name)
源码,可以看到,class.getResource(name)
最终其实是通过classLoader.getResource(name)
来获取资源文件的,如,
// class.getResource(name)方法
public java.net.URL getResource(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResource(name);
}
return cl.getResource(name);
}
其中,class.getResource(name)
首先会对name进行解析和处理,如,
// class.getResource(path)中对path预处理path = resolveName(path)
private String resolveName(String name) {
if (name == null) {
return name;
}
if (!name.startsWith("/")) {
Class<?> c = this;
while (c.isArray()) {
c = c.getComponentType();
}
String baseName = c.getName(); // 获取带包名的类名,此处是test.test
int index = baseName.lastIndexOf('.');
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/') // 给参数加上当前类所在的包的目录前缀,即在name之前加上test/test,之后会委托给classLoader来getResource(path),而classLoader默认是从项目根路径获取资源的。
+"/"+name;
}
} else {
// path以'/'开头,则去掉开头的'/',采用classLoader.getResource(去掉开头'/'后的path)来获取资源。
name = name.substring(1);
}
return name;
}
其中,如果传入的是绝对路径,那么去掉最前面的/
,然后会委托给classLoader.getResource(name)
处理;如果传入的是相对路径,那么首先获取到当前class类的完整包名,把包名中的.
替换成/
,也就是说,App类获取到包名是test.test.App
,那么会被替换成test/test/App
,然后委托给classLoader.getResource(name)
处理。
总结
class.getResource(name)
中name可以写成绝对路径/test/test/innerFile.txt
和相对路径【假设该class位于test.test包下】”innerFile.txt”,其中绝对路径的/
是相当于项目的classpath根目录,相对路径是相对于当前class的路径。而classLoader.getResource(name)
中的name一定要写成相对路径如test/test/innerFile.txt
(最前面不能是/
),并且这个相对路径是相对于项目的classpath根目录的路径,相当于class.getResource(name)
中写绝对路径/test/test/innerFile.txt
。
喜欢的可以关注微信公众号: