1. 前言
在Java中獲取資源的時候,經常用到getResource和getResourceAsStream,本文總結一下這兩種獲取資源文件的路徑差異。
2.Class.getResource(String path)
path不以'/'開頭時,默認是從此類所在的包下取資源;
path以'/'開頭時,則是從項目的ClassPath根下獲取資源。在這里'/'表示ClassPath的根目錄。
JDK設置這樣的規則,是很好理解的,path不以'/'開頭時,我們就能獲取與當前類所在的路徑相同的資源文件,而以'/'開頭時可以獲取ClassPath根下任意路徑的資源。
如下所示的例子:
public class Test { public static void main(String[] args) { System.out.println(Test.class.getResource("")); System.out.println(Test.class.getResource("/")); } }
運行結果為:
file:/D:/work_space/java/bin/net/swiftlet/
file:/D:/work_space/java/bin/
3.Class.getClassLoader().getResource(String path)
path不能以'/'開頭,path是指類加載器的加載范圍,在資源加載的過程中,使用的逐級向上委托的形式加載的,'/'表示Boot ClassLoader,類加載器中的加載范圍,因為這個類加載器是C++實現的,所以加載范圍為null。如下所示:
public class Test { public static void main(String[] args) { System.out.println(Test.class.getClassLoader().getResource("")); System.out.println(Test.class.getClassLoader().getResource("/")); } }
運行結果為:
file:/D:/work_space/java/bin/
null
從上面可以看出:
class.getResource("/") == class.getClassLoader().getResource("")
其實,Class.getResource和ClassLoader.getResource本質上是一樣的,都是使用ClassLoader.getResource加載資源的。下面請看一下jdk的Class源碼:
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和ClassLoader.getResource本質上是一樣的。至於為什么Class.getResource(String path)中path可以'/'開頭,是因為在name = resolveName(name);進行了處理:
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(); int index = baseName.lastIndexOf('.'); if (index != -1) { name = baseName.substring(0, index).replace('.', '/') +"/"+name; } } else {//如果是以"/"開頭,則去掉 name = name.substring(1); } return name; }
4.Class.getResourceAsStream(String path)
path不以'/'開頭時,默認是指所在類的相對路徑,從這個相對路徑下取資源;
path以'/'開頭時,則是從項目的ClassPath根下獲取資源,就是要寫相對於classpath根下的絕對路徑。
舉例就明白了:
com |-github |-demo | |-A.class | |-1.txt |-B.class |-2.txt
InputStream resourceAsStream = ClassLoader.getSystemResourceAsStream("com/github/demo/1.txt");
