深入理解 Java 中的资源加载

65 阅读2分钟

关注公众号 不爱总结的麦穗 将不定期推送技术好文

  我们在项目开发过程中经常会需要读取各种各样的文件(配置文件、模版文件等等),在获取资源时,一般会用到 Class.getResource() 或 ClassLoader.getResource()来获取资源的路径,Class.getResourceAsStream() 或 ClassLoader.getResourceAsStream()来获取资源的文件流。

区别

  我们通过以下的项目路径来讲解Class.getResource() 与 ClassLoader.getResource()不同

image.png

Class.getResource()

  Class.getResource() 可以从当前 Class 所在包的路径开始匹配获取资源,也可以从 classpath 根路径开始匹配获取资源。

  • 从当前包所在路径获取资源时不能以 "/" 开头
public static void readFileByStream() {

    String path="config.txt";
    System.out.println("读取文件:" + path);
    InputStream inputStream = null;
    try {
        URL resource = ThreadLocalExample.class.getResource(path);
        File file = new File(resource.getPath());
        inputStream = new FileInputStream(file);
        //输出文件内容
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int i;
        while ((i = inputStream.read()) != -1) {
            baos.write(i);
        }
        System.out.println(new String(baos.toByteArray(), StandardCharsets.UTF_8));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

image.png

  • 从 classpath 根路径获取资源时必须以 "/" 开头
public static void readFileByStream() {
    String path="/static/config.txt";
    System.out.println("读取文件:" + path);
    InputStream inputStream = null;
    try {
        URL resource = ThreadLocalExample.class.getResource(path);
        File file = new File(resource.getPath());
        inputStream = new FileInputStream(file);
        //输出文件内容
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int i;
        while ((i = inputStream.read()) != -1) {
            baos.write(i);
        }
        System.out.println(new String(baos.toByteArray(), StandardCharsets.UTF_8));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

image.png

ClassLoader().getResource()

  ClassLoader().getResource() 不能以 "/" 开头,且路径总是从 classpath 根路径开始。

public static void readFileByStream() {

    String path="static/config.txt";
    System.out.println("读取文件:" + path);
    InputStream inputStream = null;
    try {
      
        URL resource = ThreadLocalExample.class.getClassLoader().getResource(path);
        File file = new File(resource.getPath());
        inputStream = new FileInputStream(file);
        //输出文件内容
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int i;
        while ((i = inputStream.read()) != -1) {
            baos.write(i);
        }
        System.out.println(new String(baos.toByteArray(), StandardCharsets.UTF_8));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

image.png

总结

  Class.getResource()可以从当前Class所在包的路径开始匹配获取资源(不能以 "/" 开头),也可以从 classpath 根路径开始匹配获取资源(必须以 "/" 开头),ClassLoader().getResource()只能从classpath根路径开始匹配获取资源(不能以 "/" 开头),且路径总是从 classpath 根路径开始。它们都能通过 getResourceAsStream() 方法获取对应路径文件的输入流,文件路径匹配机制和其 getResource() 方法一样。