Java获取项目中的文件

Class.getResource()与ClassLoader.getResource()的区别

Class.getResource()是指AAA.class.getResource()

  1. Class.getResource(String name):在当前class类的同一路径下查找资源

  2. ClassLoader.getResource(String name):在根目录下查找该资源文件,即"/"或classpath目录

粗解

  1. 在当前项目目录下查找指定的文件,此方式只能加载当前项目classpath下的文件,用.表示当前目录,不能以/开头,会报错

    1
    2
    3
    4
    // 方式1
    URL url = ClassLoader.getSystemResource(".");
    // 方式2
    url = LoaderResourceTest.class.getClassLoader().getResource(".");

    url会输出当前class文件所在的根目录,比如当前我输出的结果就是file:/Users/chuan/Documents/projects_code/java-project/demo/demo-core/target/classes/

  2. 以当前类所在的目录为基础,在当前目录查找并加载指定名称的资源文件,比如当前类LoaderResourceTest在项目的cc.kevinlu.demo.core.loader包中,若是我们以LoaderResourceTest.class.getResource("LoaderT.class")的方式加载一个文件,则首先会在cc.kevinlu.demo.core.loader包中查找LoaderT.class文件,若查找不到则返回null,如果我们想要加载其他包中的文件,则可以使用"/"开头并加上文件在项目中的完整包路径,比如LoaderResourceTest.class.getResource("/cc/kevinlu/demo/core/gof/facade/FacadeTest.class")

    1
    2
    3
    4
    5
    // 获取当前类所在的包目录
    url = LoaderResourceTest.class.getResource(".");

    // 获取其他包内的文件
    url = LoaderResourceTest.class.getResource("/cc/kevinlu/demo/core/gof/facade/FacadeTest.class");

    这两条语句的输出:

    1
    2
    3
    file:/Users/chuan/Documents/projects_code/java-project/demo/demo-core/target/classes/cc/kevinlu/demo/core/loader/

    file:/Users/chuan/Documents/projects_code/java-project/demo/demo-core/target/classes/cc/kevinlu/demo/core/gof/facade/FacadeTest.class

    由此可以很明显的看出Class的getResource是获取当前类所在的包目录,如果不同的包中都有相同名称的资源文件,但是仅针对当前包可用,那么就可以使用这种方式去加载读取,不会出现读到其他目录的文件的情况,但是这仅受限于我们写的类,不适用于jar包中的。

  3. 如果我们想读取项目中引用的jar包内的文件,那么怎么办?其实和读取项目中自己写的文件是相同的办法,因为在系统启动的时候会将jar包中的文件加载到classpath目录下,所以读取方式一样的。

  4. 以上讲解的只是读取单个资源,那么要是想把所有匹配到的资源都获取到,则可以使用Class.getClassLoader().getResources()ClassLoader.getSystemResources()两种方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Enumeration<URL> urls = LoaderResourceTest.class.getClassLoader().getResources("META-INF/spring.factories");
    while (urls.hasMoreElements()) {
    System.out.println(urls.nextElement());
    }

    System.out.println("--ClassLoader.getSystemResources--");
    urls = ClassLoader.getSystemResources("META-INF/spring.factories");
    while (urls.hasMoreElements()) {
    System.out.println(urls.nextElement());
    }
  5. 读取资源文件内容方式

    1
    2
    3
    4
    5
    6
    InputStream is = LoaderResourceTest.class.getClassLoader().getResourceAsStream("META-INF/spring.factories");
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    String line = null;
    while ((line = br.readLine()) != null) {
    System.out.println(line);
    }

整个测试文件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package cc.kevinlu.demo.core.loader;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Enumeration;

import org.springframework.boot.admin.SpringApplicationAdminMXBean;

public class LoaderResourceTest {

public static void main(String[] args) throws Exception {

// 在当前项目目录下查找指定的文件,此方式只能加载当前项目classpath下的文件,用.表示当前目录,不能以/开头,会报错
URL url = ClassLoader.getSystemResource(".");
System.out.println(url);

// 此方式和ClassLoader.getSystemResource一样
url = LoaderResourceTest.class.getClassLoader().getResource(".");
System.out.println(url);

// 以当前类所在的目录为基础,在当前目录查找并加载指定名称的资源文件,比如当前类LoaderResourceTest在
// 项目的cc.kevinlu.demo.core.loader包中,若是我们以LoaderResourceTest.class.getResource("LoaderT.class")的
// 方式加载一个文件,则首先会在cc.kevinlu.demo.core.loader包中查找LoaderT.class文件,若查找不到则返回null,如果我们想要加载其他包中的文件,
// 则可以使用/开头并加上文件在项目中的完整包路径,比如LoaderResourceTest.class.getResource("/cc/kevinlu/demo/core/gof/facade/FacadeTest.class")
url = LoaderResourceTest.class.getResource(".");
System.out.println(url);

url = LoaderResourceTest.class.getResource("/cc/kevinlu/demo/core/gof/facade/FacadeTest.class");
System.out.println(url);

// 获取jar包内的文件有以下方式
// 1. 使用Class.getClassLoader().getResource(),这种方式只能获取第一个匹配到的文件
System.out.println("************");
url = LoaderResourceTest.class.getClassLoader().getResource("META-INF/spring.factories");
System.out.println(url);
System.out.println("************");

// 2. 使用Class.getResource(),这种方式也只能获取第一个匹配到的文件
url = LoaderResourceTest.class.getResource("META-INF/spring.factories");
System.out.println(url);

// 3. 使用ClassLoader.getSystemResource()方法,这种也仅仅只是获取第一个匹配的文件
url = ClassLoader.getSystemResource("META-INF/spring.factories");
System.out.println(url);

// 那我们如果想要获取到所有匹配到的文件要怎么办呢?那么就使用Class.getClassLoader().getResources(),这个方法会返回一个Enumeration<URL>实例,
// 我们迭代返回的这个实例就可以读取所有匹配到的所有文件了,如果没有匹配到任何文件也可以大胆的去迭代,不用判空,因为在getResources方法中进行了非空封装
System.out.println("-----");
Enumeration<URL> urls = LoaderResourceTest.class.getClassLoader().getResources("META-INF/spring.factories");
while (urls.hasMoreElements()) {
System.out.println(urls.nextElement());
}
System.out.println("-----");
urls = ClassLoader.getSystemResources("META-INF/spring.factories");
while (urls.hasMoreElements()) {
System.out.println(urls.nextElement());
}
System.out.println("-----");

// 如果想要读取文件的具体内容,那么我们就要用到文件流了,常用的方法就是使用BufferedReader去读了
// getResourceAsStream()方法,它相当于你用getResource()取得File文件后,再new InputStream(file)一样的结果
InputStream is = LoaderResourceTest.class.getClassLoader().getResourceAsStream("META-INF/spring.factories");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
int i = 1;
while (i == 1 && (line = br.readLine()) != null) {
System.out.println(line);
i++;
}

System.out.println("*******");
url = SpringApplicationAdminMXBean.class.getResource(".");
System.out.println(url);

}

}