1. 程式人生 > >Java專案中根據相對路徑和絕對路徑獲取檔案的方法 getResource(name)

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類來說),也可以是絕對路徑(絕對路徑的話,根目錄符號/

是代表專案路徑而不是磁碟的根目錄)。例如,如下兩種根據路徑獲取檔案的效果是一樣的 :

  1. App.class.getResource('innerFile.txt')
  2. 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。並且,接收的相對路徑是相對於專案的包的根目錄來說的。比如,如下兩種獲取檔案的效果是一樣的:

  1. App.class.getResource('innerFile.txt')
  2. 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();  // 獲取帶包路徑的類名,此處類名是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

喜歡的可以關注微信公眾號:
這裡寫圖片描述

參考