Java学习之如何查找资源文件 – skyWalker

最近在读取配置文件中的信息时,遇到了资源文件放置路径的问题。具体来讲就是当属性文件与类在同一包中时,使用Class.getResourceAsStream可以取得属性文件中的内容,而ClassLoader.getResourceAsStream却不能,当属性文件在类路径中时,情况正好相反。需要澄清的是两个方法的参数值为属性文件的名称,不包含路径信息。代码如下:

package test;import java.io.IOException;import java.io.InputStream;import java.util.PropertyResourceBundle;public class TestGetResourceAsStream {public static void main(String[] args) throws IOException {PropertyResourceBundle proResource;InputStream inputStream;        //当属性文件与类在同一个包中时,Class.getResourceAsStream输出属性test的值,        //ClassLoader.getResourceAsStream找不到属性文件        //当属性文件位于类路径中时,而不在类的包中时,ClassLoader.getResourceAsStream输出属性test的值,//Class.getResourceAsStream找不到属性文件inputStream = TestGetResourceAsStream.class.getResourceAsStream("test.properties");if(inputStream != null){proResource = new PropertyResourceBundle(inputStream);System.out.println("Class.getResourceAsStream: " + proResource.getString("test"));}else{                       System.out.println("Class.getResourceAsStream can not find resource on classpath");}inputStream = TestGetResourceAsStream.class        .getClassLoader().getResourceAsStream("test.properties");if(inputStream != null){proResource = new PropertyResourceBundle(inputStream);System.out.println("ClassLoader.getResourceAsStream:" + proResource.getString("test"));}else{               System.out.println("ClassLoader.getResourceAsStream can not find resource on classpath");}}}

当属性文件test.properties与类不在同一个包中时,即在包之外时,运行上述代码的输出为:

Class.getResourceAsStream can not find resource on classpathClassLoader.getResourceAsStream:Hello world!

当属性文件与类文件在同一包中时,运行结果为:

Class.getResourceAsStream:Hello world!ClassLoader.getResourceAsStream can not find resource on classpath

什么原因导致的这种差别呢?开始对此问题百思不得其解,感觉无论属性文件位于包中还是其它-classpath指定的位置,两个类中的getResourceAsStream方法都应该可以找到资源文件,但结果却不尽然,此时只能查看方法的API文档了。

首先看看Class类的getResourceAsStream方法的官方文档,文档的说明为Javai平台将该方法委托给加载该类对象的ClassLoader,如果该对象是由启动程序的ClassLoader加载的,那么该方法委托给ClassLoader.getSystemResourceAsStream(java.lang.String)。既然是委托给ClassLoader的getResourceAsStream方法,为什么输出结果却不一致呢?在此不得不继续查看官方文档,根据官方文档的说明,在委托之前需要对参数进行处理,处理逻辑为:

如果参数为null,直接返回null 如果参数不以/开头,则将参数的修改为该类所属的包名加上参数名,并将.替换为/。例如参数为hello,该类所属的包为com.test,则处理后的参数为com/test/hello。 如果参数以/开头,返回/后面的部分。例如参数为/hello,处理后的参数为hello。

Class类中的resolveName(String 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;    }

结合演示代码,两种情况下(属性文件在包中和不在包中)传入的参数都为test.properties。当属性文件在包中时,TestGetResourceAsStream.class.getResourceAsStream("test.properties")实际执行的是ClassLoader.getResourceAsStream("test/test.properties"),可以找到资源文件,而TestGetResourceAsStream.class.getClassLoader().getResourceAsStream("test.properties")却在当前路径中无法找到资源文件。这时可以通过-cp选项指定目录来解决:

D:\BigData\TestClassPath\bin>java -cp .;./test/ test.TestGetResourceAsStreamClass.getResourceAsStream:Hello world!ClassLoader.getResourceAsStream:Hello world!

当属性文件不在包中时,TestGetResourceAsStream.class.getClassLoader().getResourceAsStream("test.properties")可以在当前路径下发现资源文件,而TestGetResourceAsStream.class.getResourceAsStream("test.properties")实际执行的还是ClassLoader.getResourceAsStream("test/test.properties"),但包中却不存在test.properties文件,所以得不到属性值。

通过上面的代码演示并结合官方文档和源代码,可以得出结论,如果需要加载资源文件,最好的方法是使用ClassLoader的getResourceAsStream方法,且资源文件最好与类文件不在同一包中或者不在同一文件夹下,这样可以在将类文件打包为jar文件的情况下便于修改资源文件而无需加压缩jar文件,此时只需确保资源文件位于classpath即可。

都可以…孔子的,老子的. 孙子的…都可以

Java学习之如何查找资源文件 – skyWalker

相关文章:

你感兴趣的文章:

标签云: