java中Class.getResourceAsStream()和ClassLoader.getResourceAsStream()的區別
阿新 • • 發佈:2020-12-01
簡介
Class.getResourceAsStream()和ClassLoader.getResourceAsStream()方法都是從專案中讀取檔案,但很容易被搞混。
ClassLoader
public class Client2 { public static void main(String[] args) { //從classpath下查詢 InputStream in = Client2.class.getClassLoader().getResourceAsStream("files/asd.txt"); if (in == null) { return; } try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) { String line = null; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
我們將檔案放到classpath下,ClassLoader會直接從classpath的根目錄下查詢檔案,
輸出結果為
this is a test file2
Class
public class Client3 { public static void main(String[] args) { InputStream in = Client3.class.getResourceAsStream("/files/asd.txt"); if (in == null) { return; } try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) { String line = null; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
通過Class也可以讀到classpath下的檔案,我們需要以/開頭。
public class Client4 { public static void main(String[] args) { InputStream in = Client4.class.getResourceAsStream("abc.txt"); if (in == null) { return; } try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) { String line = null; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
我們將檔案放到當前類所在的包下,這個時候不能以/開頭,直接相對路徑就可以。
原始碼分析
public final
class Class<T> implements java.io.Serializable,
java.lang.reflect.GenericDeclaration,
java.lang.reflect.Type,
java.lang.reflect.AnnotatedElement {
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
//實際上還是呼叫ClassLoader的getResourceAsStream()方法
return cl.getResourceAsStream(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;
}
}
總結
ClassLoader從classpath下查詢,不能以/開頭,不能相對路徑,Class如果以/開頭,直接擷取/之後的路徑,不以/開頭,轉換成包含package的全路徑,內部還是呼叫的ClassLoader的方法。