Java 读取资源、配置文件

本贴最后更新于 2558 天前,其中的信息可能已经沧海桑田

Class 与 ClassLoader

写 java 代码时常常需要加载一些外部的资源,通常我们会使用全路径名加载一份资源,比如:C:\Users\XXX\Desktop\abc.jpg
但是,有些时候我们需要加载的是源代码路径下的资源或者配置文件等等,更习惯于使用相对路径,或者直接给一个文件名,就希望能够找到我们需要的配置文件。
如何做到?

常见的方法是使用了 class.getResource 或 classloader.getResource
并且使用绝对路径是一个很差的方式,它会导致你的程序移植性很差,尽量使用相对路径

这两个方法看起来很相似,他们直接有什么区别?
查看源代码:
Class.getResourceAsStream(String name)

public InputStream getResourceAsStream(String name) {

    name = resolveName(name);
	
    ClassLoader cl = getClassLoader0();

    if (cl==null) {

        // A system class.

        return ClassLoader.getSystemResourceAsStream(name);

    }

    return cl.getResourceAsStream(name);
}

上面的代码可以看出, Class.getResourceAsStream(String name) 最终还是调用了 classloader.getResourceAsStream(String name)
但是两者还是有一些区别的,注意 name =resolveName(name) 这一行, Class.getResourceAsStream(String name) 在这里做了一些处理:
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;

}

现在看这段代码还有点云里雾绕,不妨写几行代码测试一下,看看这段代码到底在干嘛:

public class App {

    public static void main(String[] args) {

        System.out.println("App.class.getClassLoader().getResource(\"\") : " + App.class.getClassLoader().getResource(""));

        System.out.println("App.class.getClassLoader().getResource(\"/\") : " + App.class.getClassLoader().getResource("/"));

        System.out.println("App.class.getResource(\"\") : " + App.class.getResource(""));

        System.out.println("App.class.getResource(\"/\") : " + App.class.getResource("/"));

    }

}

输出

App.class.getClassLoader().getResource("") : file:/D:/workspace/eclipse/cluster/TestClassloader/bin/

App.class.getClassLoader().getResource("/") : null

App.class.getResource("") : file:/D:/workspace/eclipse/cluster/TestClassloader/bin/space/yukai/

App.class.getResource("/") : file:/D:/workspace/eclipse/cluster/TestClassloader/bin/

虽然上面的代码使用了 getResource,但与 getResourceAsStream 大同小异。

可以看到,

calssloder.getResource("") 方法返回了 classpath 根路径(eclipse 工程中,编译生成的类文件存放在/bin 目录下);

calssloder.getResource("/") 方法返回 null,说明 calssloder.getResource 不支持以”/“开头的参数;

class.getResource("") 方法返回了 App.class 所在的路径;

class.getResource("/")calssloder.getResource("") 表现一致,返回了 classpath 的根路径

再回顾上面的代码,是否有一点明白了呢?

读取 jar 包所在的位置

有时候需要知道 jar 包所在的位置,比如我们的项目需要一个默认的日志文件输出路径,这个路径就可以是运行时 jar 包所在的目录。如何获取 jar 包所在的目录?

URL url = App.class.getProtectionDomain().getCodeSource().getLocation();

String path = url.toURL().getPath();

注意,上面的方法仅适用 jdk1.5 及以上

附实际使用方式


                
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3454 回帖 • 189 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...