如何为fatJar配置资源文件?基于sbt-assembly的Scala项目运行报错
解决fatJar运行时FileSystemNotFoundException问题
我之前用sbt-assembly打包Scala项目时,也碰到过一模一样的错误!问题根源在于你读取SapConfig.json的方式不对——当资源文件被打包进fatJar后,它不再是操作系统文件系统里的独立文件,而是作为zip归档的一个条目存在。如果还用java.io.File或者直接基于磁盘路径的方式去访问,JVM的ZipFileSystemProvider就找不到对应的文件系统,自然会抛出这个异常。
下面给你两种可靠的解决方案:
方案一:用输入流读取资源(推荐)
这是最通用的方式,不管资源在磁盘还是jar包内都能正常工作。在Scala里可以这么写:
import scala.io.Source import java.io.InputStream // 用类加载器获取资源输入流,注意路径开头要加/,对应resources根目录 val configStream: InputStream = getClass.getResourceAsStream("/SapConfig.json") // 读取内容并处理,记得用完关闭流(推荐用try-with-resources风格) try { val configContent = Source.fromInputStream(configStream).mkString // 在这里解析你的SapConfig.json,比如用circe、Jackson等库 } finally { if (configStream != null) configStream.close() }
如果是Scala 2.13及以上版本,还可以用标准库的Using类简化资源管理:
import scala.io.Source import scala.util.Using Using(getClass.getResourceAsStream("/SapConfig.json")) { stream => val configContent = Source.fromInputStream(stream).mkString // 处理配置逻辑 } match { case Right(_) => println("配置读取成功") case Left(ex) => println(s"读取配置失败:${ex.getMessage}") }
方案二:手动访问ZipFileSystem(适合需要Path对象的场景)
如果你的业务逻辑必须用到java.nio.file.Path(比如某些配置库要求传入Path),可以手动打开fatJar对应的ZipFileSystem来访问资源:
import java.nio.file.{Files, Paths, FileSystems} import java.net.URI // 获取当前fatJar的路径 val jarUri = getClass.getProtectionDomain.getCodeSource.getLocation.toURI val jarPath = Paths.get(jarUri) // 打开Zip文件系统,使用use方法自动关闭(Scala 2.13+支持) FileSystems.newFileSystem(jarPath, Map("create" -> "false")).use { fs => // 定位到jar内的SapConfig.json val configPath = fs.getPath("/SapConfig.json") // 读取文件内容 val configContent = Files.readString(configPath) // 处理配置 }
低版本Scala需要用try-finally手动关闭文件系统,避免资源泄漏。
额外检查:确保sbt-assembly正确打包资源
默认情况下sbt-assembly会把src/main/resources下的文件打包进fatJar,但如果你的build.sbt里自定义了assemblyMergeStrategy,要确保资源文件不会被错误过滤或覆盖:
assemblyMergeStrategy in assembly := { // 保留resources下的所有文件,遇到重复时取第一个 case PathList("resources", xs @ _*) => MergeStrategy.first // 其他合并策略根据你的项目需求调整 case x => val oldStrategy = (assemblyMergeStrategy in assembly).value oldStrategy(x) }
核心思路就是:不要用基于磁盘文件的方式访问jar包内的资源,改用输入流或者通过ZipFileSystem来操作,就能解决这个FileSystemNotFoundException问题了。
内容的提问来源于stack exchange,提问作者softshipper
相关产品推荐
相关产品推荐

