Spring Boot读取resource目录下文件失败解决方案及分析
背景
最近有个需求,就是需要从resources目录下读取文件返回给用户。在idea中运行时,有些resources下文件读取工具类能够正常获取读取到文件。但是通过java –jar的方式去运行jar包,此时resources下文件读取工具类读取文件就失效了。通过查询搜索,了解到了是读取的方式导致文件读取失败。
具体代码实现
错误的resources下文件读取写法
这部分代码展示的是通过运行jar包,ClassPathResource工具无法正常读取到文件
// 读取resource目下脚本模板文件
String templatePath = "/script/test.py";
ClassPathResource resource = new ClassPathResource(templatePath);
File file;
try {
file = resource.getFile();
} catch (IOException e) {
e.printStackTrace();
}
此处的主要做法是:通过ClassPathResource定位到resources目录下的文件,再通过他去拿到File类型的文件,通过实践证明,拿到的File是空的,说明这种方式获取文件存在问题。
正确的resources下文件读取写法
// 读取resource目下脚本模板文件
String templatePath = "/script/test.py";
ClassPathResource resource = new ClassPathResource(templatePath);
BufferedInputStream bis = new BufferedInputStream(resource.getInputStream());
以上的主要做法是:通过ClassPathResource定位到resources目录下的文件,我们只需要从ClassPathResouce对象中拿到输入流即可,通过实践证明,通过这种方式能够正常拿到文件输入流。
问题分析
为什么在打成jar包之后,不支持文件通过File定位,只能通过流或在其他方式,抱着疑惑的态度,我进入ClassPathResource类查看是否有什么提示,结果还真找到了,看如下:
/**
* {@link Resource} implementation for class path resources. Uses either a
* given {@link ClassLoader} or a given {@link Class} for loading resources.
*
* <p>Supports resolution as {@code java.io.File} if the class path
* resource resides in the file system, but not for resources in a JAR.
* Always supports resolution as URL.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 28.12.2003
* @see ClassLoader#getResourceAsStream(String)
* @see Class#getResourceAsStream(String)
*/
public class ClassPathResource extends AbstractFileResolvingResource {}
定位这句话:
* <p>Supports resolution as {@code java.io.File} if the class path
* resource resides in the file system, but not for resources in a JAR.
* Always supports resolution as URL.
大概意思就是:
如果类路径资源驻留在文件系统中,则支持解析为java.io.File,但不支持JAR中的资源。
所以大致可以理解为,我们通过java –jar运行的方式,是无法将resources下的文件解析为java.io.File的。所以当我们使用ClassPathResouce时,就可以从中读取到文件流,或者转化为URL方式进行读取。
其他方式读取resources目录下文件
InputStream inputStream = this.getClass().getClassLoader().getResource("/script/test.py").openStream();
InputStream inputStream = this.getClass().getResourceAsStream("/script/test.py");
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("/script/test.py");
InputStream inputStream = ResourceUtils.getURL("classpath:script/test.py").openStream();
以上最终都是通过resource相关工具定位到文件后,从中拿到输入流进行读取的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了