Java讀取resources資源文件-class.getResource、ClassLoader.getResource和getResourceAsStream的區別

在日常自動化測試開發中,經常要使用配置文件,或進行環境配置,或進行數據驅動等;我們常常把這些文件放置在resources目錄下,然後通過getResourceClassLoader.getResourcegetResourceAsStream()等方法去讀取,經常看到有人在讀取配置文件時踩坑,本人也是踩坑過來了,這裏做梳理分享

1、何爲classpath

讀取資源文件最關鍵的就是找到文件的位置,歸根結底就是找路徑,而怎麼找,在哪找就是個問題;這其中和classpath有很大的關係,因此先了解下classpath幫助理解

  • 我們用Java編寫的文件都是.java文件,而想要運行,還需將其編譯成.class字節碼文件纔可被JVM運行;這就需要JVM先找到對應的.class纔行,這也就是要找到對應的classpath
  • JVM會在編譯項目時,會主動將 .java文件編譯成 .class文件 並和 resources目錄下的靜態文件一起放在 target/classes(如果是test下的類,便會放於/target/test-classes下)目錄下;
    現有工程目錄如下:
    在這裏插入圖片描述
    編譯後進入target目錄下查看如下:
    在這裏插入圖片描述

2、class.getResource()

先來看getResource的用法

  • 先分別執行如下測試代碼,打印帶有"/"不帶"/"path

    import org.junit.jupiter.api.Test;
    
    public class ResourceTestDemo {
    
        @Test
        void getResourceTest(){
            System.out.println(ResourceTestDemo.class.getResource(""));
            System.out.println(ResourceTestDemo.class.getResource("/"));
           }
    

    打印結果:

    file:/Users/username/Documents/TestDev/MyTraining/XUnit/ResourceTest/target/test-classes/resourcetest/
    file:/Users/username/Documents/TestDev/MyTraining/XUnit/ResourceTest/target/test-classes/
    

    結果分析:
    1、getResource("")不帶"/“時候是從當前類所在包路徑去獲取資源
    2、getResource("/")帶”/"時候是從classpath的根路徑獲取

  • 現在來嘗試獲取resources下的文件2.txt3.txt:
    在這裏插入圖片描述
    測試代碼:

    @Test
     void getResourceFileTest(){
         System.out.println(ResourceTestDemo.class.getResource("/3.txt"));
         System.out.println(ResourceTestDemo.class.getResource("/test/2.txt"));
     }
    

    打印結果:

    file:/Users/username/Documents/TestDev/MyTraining/XUnit/ResourceTest/target/classes/3.txt
    file:/Users/username/Documents/TestDev/MyTraining/XUnit/ResourceTest/target/classes/test/2.txt
    

3、getClassLoader().getResource()

  • 和上述一樣,先分別執行測試代碼,打印帶有"/"不帶"/"path
     @Test
     void getClassLoaderResourceTest(){
         System.out.println(ResourceTestDemo.class.getClassLoader().getResource(""));
         System.out.println(ResourceTestDemo.class.getClassLoader().getResource("/"));
     }
    
    打印結果:
    file:/Users/qinzhen/Documents/TestDev/MyTraining/XUnit/ResourceTest/target/test-classes/
    null
    
    結果分析:
    1、 getClassLoader().getResource("")不帶"/“時候是從classpath的根路徑獲取
    2、 getClassLoader().getResource("/")帶有”/"打印爲null,路徑中無法帶有"/"
  • 現在繼續嘗試獲取resources下的文件2.txt3.txt:
    @Test
    void getClassLoaderResourceFileTest(){
        System.out.println(ResourceTestDemo.class.getClassLoader().getResource("3.txt"));
        System.out.println(ResourceTestDemo.class.getClassLoader().getResource("test/2.txt"));
    }
    
    打印結果:
    file:/Users/qinzhen/Documents/TestDev/MyTraining/XUnit/ResourceTest/target/classes/3.txt
    file:/Users/qinzhen/Documents/TestDev/MyTraining/XUnit/ResourceTest/target/classes/test/2.txt
    

4、getResourceAsStream()

getResourceAsStream() 方法僅僅是獲取對應路徑文件的輸入流,在路徑的用法上與getResource()一致

5、補充

其實當我們查看class.getResource的源碼時發現如下:

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);
}

其實這裏也是調用了getClassLoader,只是方便了我們使用而已

6、總結

  • class.getResource()不帶"/"時候是從當前類所在包路徑去獲取資源
  • class.getResource()帶"/"時候是從classpath的根路徑獲取
  • class.getResource()本質上也是調用了getClassLoader,只是封裝了一層方便了我們使用而已
  • getClassLoader().getResource("")不帶"/"時候是從classpath的根路徑獲取
  • getClassLoader().getResource("/")路徑中無法帶有"/"
  • getResourceAsStream() 方法僅僅是獲取對應路徑文件的輸入流,在路徑的用法上與getResource()一致
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章