如何获取经sbt打包项目中指定资源目录内的文件列表?
解决sbt universal打包后资源目录访问问题
嘿,我完全懂你遇到的坑——当用sbt universal:packageBin打包后,src/main/resources下的资源不再是磁盘上的真实目录,而是被打包进了归档文件(比如jar或者zip包)里,这时候直接用File类去操作肯定会翻车,因为getResource返回的URL根本不是普通的文件路径。
为什么原来的方法行不通?
getClass.getResourceAsStream("/public/images/"):这个方法只对单个文件有效,目录本身不是一个可读取的“文件”,所以返回null是正常的。getClass.getResource("/public/images/"):打包后这个URL的协议是jar:而不是file:,File类根本无法识别这种归档内的路径,所以isDirectory()返回false,调用listFiles()自然会抛出异常。
最优解决方案分两种情况
情况1:你知道目录下的具体文件名(比如asd1.png、asd2.png)
这是最简单的场景,直接单个加载资源就好,不管是开发环境还是打包后都能正常工作:
// 加载单个图片资源 val imageStream = getClass.getResourceAsStream("/public/images/asd1.png") // 之后就可以用这个流做你需要的操作,比如读取图片内容
情况2:需要动态遍历目录下的所有文件
如果必须要遍历目录,就得兼容**开发时(磁盘目录)和打包后(归档内)**两种场景。可以写一个工具方法来处理不同的URL协议:
import java.io._ import java.net.{URL, URLDecoder} import java.util.jar.JarFile object ResourceUtils { // 传入资源目录的路径(必须以/开头,比如"/public/images/") def listResourceFiles(dirPath: String): List[String] = { val resourceUrl = getClass.getResource(dirPath) if (resourceUrl == null) return Nil resourceUrl.getProtocol match { // 开发环境:资源在磁盘目录 case "file" => val dir = new File(URLDecoder.decode(resourceUrl.getPath, "UTF-8")) if (dir.isDirectory) { dir.listFiles() .filter(_.isFile) .map(file => s"$dirPath${file.getName}") .toList } else Nil // 打包后:资源在Jar/Zip归档内 case "jar" => // 解析Jar文件路径 val jarFullPath = resourceUrl.getPath.substring(5, resourceUrl.getPath.indexOf("!")) val jarFile = new JarFile(URLDecoder.decode(jarFullPath, "UTF-8")) val entries = jarFile.entries() val resourcePaths = collection.mutable.ListBuffer[String]() while (entries.hasMoreElements) { val entry = entries.nextElement() val entryName = entry.getName // 筛选出目标目录下的文件(排除子目录) if (entryName.startsWith(dirPath.stripSuffix("/")) && !entry.isDirectory) { resourcePaths.addOne(s"/$entryName") } } jarFile.close() resourcePaths.toList // 其他协议(比如war等),根据需要扩展 case _ => Nil } } }
使用示例:
// 获取public/images下所有文件的路径 val imagePaths = ResourceUtils.listResourceFiles("/public/images/") // 遍历加载每个资源 imagePaths.foreach { path => val stream = getClass.getResourceAsStream(path) // 处理资源流... }
额外注意事项
- 确保传入的目录路径以
/开头,避免匹配到类似public/imagesOther这种无关路径 - 记得对URL路径解码,防止路径里的空格、特殊字符导致错误
- 使用
JarFile后一定要关闭,避免资源泄漏 - 如果你的项目用了Play、Spring Boot这类框架,直接用它们提供的资源加载工具会更省心(比如Spring的
ResourceLoader)
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

