列出sbt 1.2.8中资源目录中的文件

时间:2019-04-03 10:36:22

标签: scala sbt

我有一个scala应用程序,该应用程序处理resources中某个目录中的二进制文件。我想将此目录作为java.io.File并列出所有内容。在最新的sbt中,我无法直接进行操作。

我已为问题创建了最小的回购协议:

https://github.com/mat646/sbt-resource-bug

sbt 0.13.18及更低版本不会发生此问题。 因此,经过一些研究,我发现自sbt 1.0起,设计已更改,并且此问题已在此处解决:

https://github.com/sbt/sbt/issues/3963

因此提供的解决方案是:
1.降级到sbt 0.13(我想避免)
2.解压缩项目jar本身(我发现这很麻烦,因为我还没有解决-https://github.com/sbt/io包含gunzip方法,但是对我来说,它仍然无法从jar中解压缩我的目录,但是在这里我可能会误会如何从项目jar中提取嵌套文件)
(因此sbt 1.0+可以在构建jar上读取文件getResourceAsStream的情况下工作正常,但因我的问题而失败)

感谢您提供帮助和解决方法!

1 个答案:

答案 0 :(得分:3)

run任务似乎已经在Forward run task to bgRun #3477中进行了重新布线,其副作用之一是在类路径而不是类目录上使用打包的jar,以便getClass.getResource("/my-dir")返回

jar:file:/var/folders/84/hm7trc012j19rbgtn2h4fg6c0000gp/T/sbt_1397efb8/job-1/target/43a04671/sbt-resource-bug_2.12-0.1.jar!/my-dir

代替

file:/Users/amani/IdeaProjects/sbt-resource-bug/target/scala-2.12/classes/my-dir

解决方法1:将run重新定义为旧的行为

作为一种解决方法,我们可以尝试像这样来还原build.sbt中的重新布线:

run := Defaults.runTask(fullClasspath in Runtime, mainClass in run in Compile, runner in run).evaluated

例如,File.listFiles现在应该可以工作

new File(getClass.getResource("/my-dir").getFile).listFiles().foreach(println)

应输出

sbt:sbt-resource-bug> run
[info] Running Main 
/Users/mario/IdeaProjects/sbt-resource-bug/target/scala-2.12/classes/my-dir/file2.txt
/Users/mario/IdeaProjects/sbt-resource-bug/target/scala-2.12/classes/my-dir/file1.txt

解决方法2:使用JarFile直接使用JAR

或者,如果我们希望保持当前的连接状态,可以使用JarFile列出JAR文件的内容。例如,给定

object ListFileNamesInJarDirectory {
  def apply(dir: String): List[String] = {
    import scala.collection.JavaConverters.enumerationAsScalaIteratorConverter
    val jar = new File(getClass.getProtectionDomain().getCodeSource().getLocation().getPath())
    (new JarFile(jar))
      .entries()
      .asScala
      .toList
      .filter(!_.isDirectory)
      .filter(entry => entry.getRealName.contains(dir))
      .map(_.getName)
  }
}

然后

ListFileNamesInJarDirectory("my-dir").foreach(println)

应输出

my-dir/file1.txt
my-dir/file2.txt

然后,getResourceAsStream可用于获取jar中的实际文件。注意how得到File代表jar文件:

val jar = new File(getClass.getProtectionDomain().getCodeSource().getLocation().getPath())