sbt项目中如何通过Slick加载jar包内的二进制SQLite数据库文件
问题根因
SQLite JDBC 驱动仅能读取文件系统中真实存在的物理文件,你发布后获取的路径是JAR包内部资源的虚拟路径(带!标识),不属于操作系统可直接访问的文件路径,因此连接失败。
可行解决方案
推荐采用「运行时解压资源到临时目录」的方案,实现成本低、兼容性强,具体步骤如下:
步骤1:编写资源解压逻辑
在Sample.scala中新增将JAR内data.db复制到本地临时目录的代码,示例如下:
import java.io.{File, FileOutputStream} import slick.jdbc.JdbcBackend.Database // 临时目录存储路径,可根据需求调整为用户指定目录或应用缓存目录 private val tempDbPath = s"${System.getProperty("java.io.tmpdir")}/testkit_sample_data.db" private val tempDbFile = new File(tempDbPath) // 仅当临时文件不存在时复制,避免每次运行重复覆盖 if (!tempDbFile.exists()) { val resourceStream = getClass.getResourceAsStream("/data.db") require(resourceStream != null, "内置示例数据库文件不存在") val outputStream = new FileOutputStream(tempDbFile) // 流拷贝 resourceStream.transferTo(outputStream) resourceStream.close() outputStream.close() // 可选:设置文件只读权限,避免其他用户篡改 tempDbFile.setWritable(false) } // 用临时文件的真实路径创建连接 val conn = Database.forURL(s"jdbc:sqlite:$tempDbPath", prop = Map.empty[String, String])
注:以上代码中
transferTo为Java 9+ API,若使用Java 8环境,可替换为手动字节流拷贝逻辑:val buffer = new Array[Byte](1024) var readLen: Int = 0 while ({readLen = resourceStream.read(buffer); readLen != -1}) { outputStream.write(buffer, 0, readLen) }
可选优化点
- 如果需要支持示例数据更新,可以在打包时给
data.db加版本标识,运行时比对本地临时文件的版本,版本不一致时重新复制 - 如果临时目录被系统清理,代码会自动重新生成文件,无需额外处理
- 不需要额外修改sbt打包配置,原有资源打包逻辑保持不变即可
其他可选方案(不推荐)
可以使用支持ZIP/JAR内资源读取的扩展SQLite驱动,但兼容性差,不同操作系统、JDK版本容易出现适配问题,生产环境不建议使用。
内容的提问来源于stack exchange,提问作者yuez
相关产品推荐
相关产品推荐

