Kotlin执行Gradle distTar后无法读取src/main/resources文件
解决Jar包中读取resources目录下文件的问题
我太懂这种踩坑的感觉了——开发时能正常读取src/main/resources/user.json,但用Gradle的distTar打包成Jar后就抛出FileNotFoundException,核心原因是:Jar里的资源不是操作系统文件系统中的真实文件,而是嵌入在Jar内部的一个资源条目,file:/app/api-latest/lib/api-latest.jar!/user.json这种路径并不是一个真实的文件路径,File类根本无法解析它。
为什么你之前的方式都不行?
不管你怎么构造File对象,只要是用文件系统路径去访问Jar内的资源,必然会失败——因为File类只能操作操作系统文件系统中存在的实体文件,而Jar内的资源是被压缩在Jar包里的,不属于文件系统的一部分。
正确的访问方式(Kotlin实现)
下面几种方式不管是开发环境还是打包成Jar后都能正常工作:
1. 最推荐:用类加载器获取输入流直接读取
这是通用且安全的方式,直接从类路径加载资源的输入流:
fun readFileFromResources(filename: String): String { // 用当前类的类加载器获取资源输入流 return this::class.java.classLoader.getResourceAsStream(filename)?.use { inputStream -> // use函数会自动关闭流,避免资源泄漏 inputStream.bufferedReader().readText() } ?: throw IllegalArgumentException("找不到资源文件:$filename") }
调用的时候直接传"user.json"就行,因为src/main/resources下的文件会被打包到Jar的类路径根目录。
2. 获取资源URL后打开流(适合需要URL的场景)
如果你需要获取资源的URL(比如某些API要求传入URL),可以用getResource,但绝对不能把URL转成File,而是要通过URL打开输入流:
fun readResourceByUrl(filename: String): String { val resourceUrl = this::class.java.classLoader.getResource(filename) ?: throw IllegalArgumentException("找不到资源文件:$filename") return resourceUrl.openStream().use { inputStream -> inputStream.bufferedReader().readText() } }
3. Spring/Spring Boot项目专属:用框架工具类
如果你的项目是Spring或Spring Boot,可以直接用框架提供的ResourceUtils简化操作:
import org.springframework.util.ResourceUtils fun readSpringResource(filename: String): String { val resourceUrl = ResourceUtils.getURL("classpath:$filename") return resourceUrl.openStream().use { inputStream -> inputStream.bufferedReader().readText() } }
额外检查事项
- 确认
user.json确实在src/main/resources目录下,打包后可以用jar tf api-latest.jar命令查看Jar内容,确保根目录下有user.json; - 文件名注意大小写,类加载器查找资源时是严格区分大小写的;
- 永远不要尝试将Jar内的资源路径转换成
File对象,这是不可能成功的——Jar内的资源不是独立文件。
内容的提问来源于stack exchange,提问作者Jakob Nielsen
相关产品推荐
相关产品推荐

