Class.getResourceAsStream() 和ClassLoader.getResourceAsStream()路径问题
-
为什么要搞清楚这个东西。
- 在进行xml解析,获取xml文件流中
- 在获取properties文件流时
- 在获取其他文件的文件流时
-
两者的相对路径和绝对路径问题通过试验的方式得出结论
/*编译后的class文件路径 * |-src(com的上一级目录,名称和开发环境有关) |----com |-----|----xxx |-----|-----|----test |-----|-----|-----|----Test.class |-----|-----|-----|----a.txt |---a.xml |---db.properties */ //编译后文件的层次关系如上图所示 //api中关于getResourceAsStream()的介绍,其方法本质时通过getResource()获取到url在封装成流 //为了试验方便,则使用getResource()进行测试 /*在委托前,使用下面的算法从给定的资源名构造一个绝对资源名: 如果 name 以 '/' 开始 ('\u002f'),则绝对资源名是 '/' 后面的 name 的一部分。 否则,绝对名具有以下形式: modified_package_name/name 其中 modified_package_name 是此对象的包名,该名用 '/' 取代了 '.' ('\u002e')。 */ package com.xxx.test; import java.net.URL; public class Test { public static void main(String[] args) { URL url = Test.class.getResource("a.txt"); URL url1 = Test.class.getResource("/a.xml"); URL url2 = Test.class.getClassLoader().getResource("db.properties"); String path = url.getPath(); String path1 = url1.getPath(); String path2 = url2 .getPath(); System.out.println("class.get..的相对路径位置:"+path); System.out.println("class.get..的绝对路径位置:"+path1); System.out.println("classloader.get..的相对路径位置:"+path2); } } /* 结果:(其中ResourceAsStream为com包的上一级目录) class.get..的相对路径位置: /C:/.../ResourceAsStream/com/xxx/test/a.txt class.get..的绝对路径位置: /C:/.../ResourceAsStream/a.xml classloader.get..的相对路径位置: /C:/.../ResourceAsStream/db.properties */ /* 分析: 根据api描述,getResource()方法没有相对路径的概念,都是绝对路径,其根路径在src下 如果是class.getResource()的名义向的相对路径(不带/)的:在原路径上加上该类的包名 即com/xxx/test/a.txt作为绝对路径。绝对路径的根就是src下的根ResourceAsStream/绝对路径 如果是classLoader.getResource(“不带/+path”)方法,则默认把path作为绝对路径。和class.getResource("带/+path")相同。 */ //查看源码: 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()方法线调用了resolveName方法进行路径的解析。在调用classLoader的getReSrouce(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; } //class的resolveName(String name)对name进行解析。可以发现,在有/的时候是调用了: //name.substring(1)把“/”去掉,再调用classLoader.getResource(String name)方法,与我们观察到的结果一致。 //当没有“/”时会再name前面把包名的点“.”替换为"/"并作为路径加在name的前面作为绝对路径。 //classLoader.getResource(String name) name值只能使用不带“/”的路径 URL url4 = Test.class.getClassLoader().getResource("/db.properties"); System.out.println(url4);//打印结果为null。找不到该路径。
结论:
1、getResourceAsStream(String name) 底层时调用了getResource()方法,两者的路径写法一致
2、使用class的getResource(String name) 方法:
1、如果以/开头+path 那么绝对路径为 包名上一级目录(这里是com的上一级目录)/+path;
2、如果没有以/开头+path 那么绝对路径为 包名上一级目录/该类的包名路径(把包名的点替换为/)+“/”+path
3、使用classLoader的getResource(String name) 方法:
1、name中不能带有/
2、路径为src(项目名)+“/”+name
4、注意:路径关系是编译后的项目文件。不是在IDE中的开发目录下的路径
比如在maven中开发目录下java下是包名+类名 resource下是资源文件
在编译后是在target下的classes下有包文件以及资源文件