【问题标题】:How to access static resources in jar (that correspond to src/main/resources folder)?如何访问 jar 中的静态资源(对应于 src/main/resources 文件夹)?
【发布时间】:2014-11-21 13:19:57
【问题描述】:

我有一个使用 Maven(作为 jar)构建并使用 spark-submit 脚本部署的 Spark Streaming 应用程序。应用项目布局遵循标准目录布局:

myApp
    src
        main
            scala
                com.mycompany.package
                      MyApp.scala
                      DoSomething.scala
                      ...
            resources
                aPerlScript.pl
                 ...
        test
           scala
                com.mycompany.package
                      MyAppTest.scala
                      ...
        target
           ...
pom.xml

DoSomething.scala 对象中,我有一个方法(我们称之为doSomething())尝试执行Perl 脚本——aPerlScript.pl(来自resources 文件夹)——使用scala.sys.process.Process 并传递两个脚本的参数(第一个是用作输入的二进制文件的绝对路径,第二个是生成的输出文件的路径/名称)。然后我打电话给DoSomething.doSomething()

问题是我无法访问脚本,不是绝对路径、相对路径、getClass.getClassLoader.getResource、getClass.getResource,我在pom.xml 中指定了资源文件夹。我的尝试都没有成功。我不知道如何找到我放在 src/main/resources 中的东西。

我将不胜感激。

旁注:

  • 我使用外部流程而不是 Spark 管道,因为在我的工作流程的这一步,我必须处理二进制文件作为输入和输出。
  • 我正在使用 Spark-streaming 1.1.0、Scala 2.10.4 和 Java 7。我使用 Eclipse (Kepler) 中的“Maven install”构建 jar
  • 当我使用getClass.getClassLoader.getResource“标准”方法访问资源时,我发现实际的类路径是spark-submit 脚本的路径。

【问题讨论】:

  • 你能gist.github.com Scala 中访问静态资源的代码吗?您的问题似乎与 Spark 本身无关,而是关于如何在 Scala 中访问类路径上的静态资源的一般问题。请帮助我了解我错了多少。

标签: scala maven spark-streaming


【解决方案1】:

有几个解决方案。最简单的是使用 Scala 的流程基础架构:

import scala.sys.process._

object RunScript {
  val arg = "some argument"
  val stream = RunScript.getClass.getClassLoader.getResourceAsStream("aPerlScript.pl")
  val ret: Int = (s"/usr/bin/perl - $arg" #< stream).!
}

在这种情况下,ret 是进程的返回码,进程的任何输出都将定向到 stdout

第二种(更长的)解决方案是将文件 aPerlScript.pl 从 jar 文件复制到某个临时位置并从那里执行它。这段代码 sn-p 应该有你需要的大部分。

object RunScript {
  // Set up copy destination from the Java temporary directory. This is /tmp on Linux
  val destDir = System.getProperty("java.io.tmpdir") + "/"
  // Get a stream to the script in the resources dir
  val source = Channels.newChannel(RunScript.getClass.getClassLoader.getResourceAsStream("aPerlScript.pl"))
  val fileOut = new File(destDir, "aPerlScript.pl")
  val dest = new FileOutputStream(fileOut)
  // Copy file to temporary directory
  dest.getChannel.transferFrom(source, 0, Long.MaxValue)
  source.close()
  dest.close()
}
// Schedule the file for deletion for when the JVM quits
sys.addShutdownHook {
  new File(destDir, "aPerlScript.pl").delete
}
// Now you can execute the script.

这种方法允许您将本机库捆绑到 JAR 文件中。将它们复制出来可以在运行时为您计划的任何 JNI 恶作剧加载库。

【讨论】:

  • 嗨@david-weber,感谢您的回答。这个解决方案可能是一个实际上可行的选项。确切地说,在我的情况下,我还必须声明资源路径,即:val source = Channels.newChannel(LibLoader.getClass.getClassLoader.getResourceAsStream("resources/aPerlScript.pl"))
  • 我对你的答案投了赞成票,但目前我决定不将其标记为已接受的答案,因为我仍然需要一种方法来运行 aPerlScript.pl 无需先将其复制到本地目录。顺便说一句,非常感谢。
  • 其实很长。我的 spark 流应用程序需要为每个输入项调用它!
  • 这个太简单了。查看修复。
猜你喜欢
  • 2017-10-03
  • 2016-03-06
  • 2016-07-22
  • 1970-01-01
  • 1970-01-01
  • 2017-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多