SpringBoot 实战:加载和读取资源文件

SpringBoot 实战:加载和读取资源文件

该图片由Marna Buys在Pixabay上发布


你好,我是看山。


本文聊一聊在 SpringBoot 应用中,访问加载类路径(classpath)中的文件内容的多种方法。


通过Resource接口

Resource接口抽象出一种更底层的方式管理资源,可以实现通过统一的方式处理各类文件资源。下面是几种获取资源实例的方法。


手动加载

访问类路径中的文件,我们可以直接使用ClassPathResource加载内容,比如:


new ClassPathResource("data/resource-data.txt");

默认情况下,ClassPathResource会在线程的上下文类加载器和默认系统类加载器之间进行选择,以删除样板文件。我们也可以直接指定类加载器,比如:


new ClassPathResource("data/resource-data.txt", this.getClass().getClassLoader());

1

或者是通过指定类的类加载器:


new ClassPathResource("data/resource-data.txt", Employee.class.getClassLoader());

从Resource对象,我们可以很容易的将其转换为InputStream或File对象。


上面说的方式都是相对于类路径的地址。如果想要指定某个类的相对路径,我们和可以通过指定具体类来定义,比如:


new ClassPathResource("../../../data/resource-data.txt", Example.class).getFile();

这样就是相对于Example的相对路径了。在实际使用中,不太建议通过类获取其相对路径的文件。这样会将类与文件的相对坐标绑定,如果修改了类的包路径,但是忘记修改文件位置,就会出现错误。而且,大家现在一般是使用 Maven 之类的包管理器管理,可以直接在resources目录中定义配置文件,使用类路径的相对地址加载文件即可。


通过@Value自动转换

我们还可以使用@Value直接注入Resource对象,比如:

@Value("classpath:data/resource-data.txt")
Resource resourceFile;

@Value还能支持其他的加载协议,比如file:或url:。


通过ResourceLoader加载

我们还能使用注入ResourceLoader来实现资源的懒加载,比如,先注入ResourceLoader实例:


@Autowired
ResourceLoader resourceLoader;

然后在我们需要的地方,通过ResourceLoader实例加载资源:


resourceLoader.getResource("classpath:data/resource-data.txt");

在 Spring 中,ApplicationContext实现了ResourceLoader,所以,我们也可以直接通过ApplicationContext实例加载资源,比如:


ApplicationContext context;

public Resource loadEmployeesWithApplicationContext() {
    return context.getResource("classpath:data/resource-data.txt");
}

使用ResourceUtils加载资源

在 Spring 内部,还提供了一个工具类ResourceUtils,可以很方便的获取类路径中额资源。但是通过这个类的 Javadoc 可以看到,这个类主要是在 Spring 内部使用,也就是说,不太推荐这种用法。不过我们可以了解一下:


public File loadEmployeesWithSpringInternalClass() 
  throws FileNotFoundException {
    return ResourceUtils.getFile(
      "classpath:data/resource-data.txt");
}

我们可以了解其内部实现,但是还是建议使用其他更加标准的做法。


读取资源中的内容

上面都是通过各种方式获取了Resource资源,接下来我们就聊聊如果获取资源对象的数据。


比如,我们的资源文件内容如下:


站点:https://www.howardliu.cn
作者:看山
公号:看山的小屋 (kanshanshuo)
关注公号得福利:不知道多少 G 的资料(电子书、视频等等)

通过File对象读取

我们可以使用getFile方法得到File实例,就可以用读取File对象的方式读取文件了,比如:


@Test
File resource = new ClassPathResource("data/resource-data.txt").getFile();
String content = new String(Files.readAllBytes(resource.toPath()));

但是这种方式不适用与读取 jar 包中的文件,鉴于现在很多应用都是通过 FatJar 方式部署,我们还需要找找其他方式。


通过InputStream对象读取

File对象不适合 jar 包中资源读取的原因在于文件路径格式不一样,所以我们可以直接将资源内容读取为流的形式,这样就没有文件路径的问题了。比如:

InputStream resource = new ClassPathResource("data/resource-data.txt").getInputStream();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource))) {
    String content = reader.lines().collect(Collectors.joining("\n"));
}

读取完毕。


文末总结

本文从加载资源、读取内容两个方法讲解,给出了多种读取方式。


《SpringBoot 实战》是一个系列,我会通过实战+原理的方式完整整个专栏,可以关注公众号「看山的小屋」回复 spring 获取源码。


推荐阅读

SpringBoot 实战:一招实现结果的优雅响应

SpringBoot 实战:如何优雅的处理异常

SpringBoot 实战:通过 BeanPostProcessor 动态注入 ID 生成器

SpringBoot 实战:自定义 Filter 优雅获取请求参数和响应结果

SpringBoot 实战:优雅的使用枚举参数

SpringBoot 实战:优雅的使用枚举参数(原理篇)

SpringBoot 实战:在 RequestBody 中优雅的使用枚举参数

SpringBoot 实战:在 RequestBody 中优雅的使用枚举参数(原理篇)

SpringBoot 实战:JUnit5+MockMvc+Mockito 做好单元测试

SpringBoot 实战:加载和读取资源文件内容

上一篇:SpringBoot 实战:JUnit5+MockMvc+Mockito 做好单元测试


下一篇:为什么 MySQL 不推荐使用 join?