Java專案中根據相對路徑和絕對路徑獲取檔案的方法 getResource(name)
首先,專案中檔案分佈情況如下,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')
介紹完了這兩種,那麼應該能夠根據這兩種方法分別獲取到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(); // 獲取帶包路徑的類名,此處類名是App,包的路徑是test.test,所以baseName就是test.test.App。
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
。
喜歡的可以關注微信公眾號: