java中Class.getResourceAsStream()和ClassLoader.getResourceAsStream()的区别
简介
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的方法。