本文為霍格沃茲測試學院優秀學員學習筆記,進階學習文末加群。
在日常自動化測試開發工作中,經常要使用配置文件,進行環境配置,或進行數據驅動等。我們常常把這些文件放置在 resources 目錄下,然后通過 getResource、ClassLoader.getResource 和 getResourceAsStream() 等方法去讀取。經常看到有不少同學在讀取配置文件時踩坑,本人也是一路踩坑摸索過來,這里做一個簡要梳理,供大家參考。
一、何為 classpath ?
讀取資源文件最關鍵的就是找到文件的位置,歸根結底就是找路徑,而怎么找,在哪找就是個問題。這其中和 classpath 有很大關系,因此我們先了解下 classpath 的概念,幫助理清思路。
- 我們用 JAVA 編寫的文件都是 .java 文件,而想要運行,還需將其編譯成 .class 字節碼文件才可被 JVM 運行;這就需要 JVM 先找到對應的 .class 才行,這也就是要找到對應的classpath。
- JVM 會在編譯項目時,會主動將 .java 文件編譯成 .class 文件 并和 resources目錄下的靜態文件一起放在 target/classes (如果是 test 下的類,便會放于 /target/test-classes 下)目錄下;
現有工程目錄如下:

編譯后進入 target 目錄下查看如下:

二、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.txt和3.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
三、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.txt和3.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
四、getResourceAsStream()
getResourceAsStream() 方法僅僅是獲取對應路徑文件的輸入流,在路徑的用法上與getResource()一致。
補充
其實當我們查看 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,只是方便了我們使用而已。
總結
- class.getResource()不帶"/"時候是從當前類所在包路徑去獲取資源;
- class.getResource()帶"/"時候是從classpath的根路徑獲取;
- class.getResource()本質上也是調用了getClassLoader,只是封裝了一層方便了我們使用而已;
- getClassLoader().getResource("")不帶"/"時候是從classpath的根路徑獲取;
- getClassLoader().getResource("/")路徑中無法帶有"/";
- getResourceAsStream() 方法僅僅是獲取對應路徑文件的輸入流,在路徑的用法上與getResource()一致;
以上,供大家探討。