我有一个小火花程序使用Scala,我想把它打包成一个可执行的fat-jar,配置在文件中设置:src/main/resource/localconfig.properties
,所以我在{{1}中新建了org.apache.hadoop.fs.Path(String pathString)
的实例}}:
src/main/scala/com.let.App
问题是它可以在IDEA上运行但在jar中使用val Path = new Path("localconfig.properties")
运行时失败,提示:找不到文件。
我提取jar并且属性文件位于根文件夹中:myapp,我也尝试了java -jar myapp.jar
,但它也不起作用。
如何在可执行jar中为Path设置正确的路径?
这是windows环境,我读了它似乎与OS有关的Path()方法,但我仍然不知道如何使用构造函数。
答案 0 :(得分:0)
从String构造路径。路径字符串是URI,但是使用未转义的元素和一些额外的规范化。
这意味着pathString
(例如示例中的localconfig.properties
)应该在文件系统上可用,显然不是这种情况。该文件位于jar文件中,因此您应该让JVM为您提供文件。
这就是你应该使用Hadoop HDFS的Path(URI aUri)和Java的ClassLoader.getResource方法的地方。
$ jar cvf /tmp/hello.jar hello.xml
$ jar -tf /tmp/hello.jar
META-INF/
META-INF/MANIFEST.MF
hello.xml
// start spark-shell with the jar on the CLASSPATH
// that should be exactly your case where your jar is on CLASSPATH
// with the file you want to use to construct Path inside
$ ./bin/spark-shell --jars /tmp/hello.jar
scala> this.getClass.getResource("/hello.xml")
res0: java.net.URL = jar:file:/tmp/hello.jar!/hello.xml
// Convert URL to URI that Path supports
scala> this.getClass.getResource("/hello.xml").toURI
res1: java.net.URI = jar:file:/tmp/hello.jar!/hello.xml
scala> import org.apache.hadoop.fs.Path
import org.apache.hadoop.fs.Path
scala> new Path(this.getClass.getResource("/hello.xml").toURI)
res3: org.apache.hadoop.fs.Path = jar:
但我不知道是否支持这样构建Path
。
答案 1 :(得分:0)
我不确定它是否仍然打开,但是在尝试访问Spark应用程序的参考数据时遇到了这个问题。 Jacek的答案很接近,但遇到了一个常见的hadoop问题,即路径无法处理多个:
分隔方案,因此jar:file:
仅映射到jar:
下的hadoop.fs.Path
上。这通常表现为有关相对路径的错误。
我发现的唯一解决方法是以InputStream
的形式访问jar资源,然后将该InputStream
复制到一个临时(本地)文件并从那里加载它。这不是超级高效,也不是特别漂亮,但是它似乎可以工作(我敢肯定其他人也会遇到写权限问题,但我还没有)。
import org.apache.commons.io.FileUtils
val resourceName: String = "myResource.tsv"
val inputStream: InputStream = YourClass.getClass.getResourceAsStream(resourceName)
val tmpDir: String = FileUtils.getTempDirectoryPath // You need write permissions here
val outPath: java.nio.file.Path = java.nio.file.Paths.get(tmpDir, resourceName)
val outUriString: String = outPath.toUri.toString // Need full URI
val java.nio.file.Files.copy(inputStream, outPath) // Signature requires (InputStream, Path)
new java.io.File(outUriString).deleteOnExit() // Delete temp file after execution
/* You should be able to access the local file now, e.g. */
val data = spark.read.csv(outUriString)