惯用Clojure将资源从运行jar复制到外部

Log*_*aga 7 java io copy jar clojure

这似乎是一个经典问题,但我找不到任何关于它的"clojure方式".

所以,我在resources /(leiningen项目)里面有一个foo /目录.当jar'd/uberjar'd时,这个foo /目录放在jar的根目录下.由于jar中的文件在运行时可能不是物理上一致的,因此您无法使用基本复制功能以递归方式将目录复制到外部世界.

存在几种Java世界的解决方案(如何编写可以提取JAR文件并将其数据存储在指定目录(位置)中的Java程序?以及如何从jar资源中提取目录(和子目录)?)但是我没有找到任何现有的Clojure解决方案.作为初学者(包括Clojure和Java),我不确定如何将上述解决方案转换为Clojure.逐字逐句地从Java翻译成Clojurish Java Interop似乎不对.有没有"官方",clojure-idiomatic方式来做到这一点?

请注意,我正在使用Raynes的fs实用程序库.似乎没有直接执行此功能的功能,但也许我可以使用一些元素来简化流程?(除了明显的基本io糖)

xsc*_*xsc 5

几个月前我写了cpath-clj,它将通过 URI 列出类路径上的资源。然后您可以尝试以下操作:

(require '[cpath-clj.core :as cp]
         '[clojure.java.io :as io])

(doseq [[path uris] (cp/resources (io/resource "foo"))
        :let [uri (first uris)
              relative-path (subs path 1)
              output-file (io/file output-directory relative-path)]]
  (with-open [in (io/input-stream uri)]
    (io/copy in output-file)))
Run Code Online (Sandbox Code Playgroud)

由于库不是在考虑这个用例的情况下编写的,所以有一些杂耍正在进行:

  • (cp/resources (io/resource "foo"))将为您提供 foo目录的内容- 如果您只使用(cp/resources "foo")类路径上的所有此类目录,就会找到,
  • 理论上,path类路径上可以有多个相同的文件,这就是函数返回多个uris; 在我们的例子中,只有第一个是感兴趣的。
  • path 总是以斜杠开头,因此要获得相对的斜杠,我们必须将其删除。

也许这对你有帮助。


小智 0

我不确定惯用部分,但资源目录中的文件可以这样列出

(defn list-resource
  [resource-dir]
  (let [resource (io/file (io/resource resource-dir))]
    (file-seq resource)))
Run Code Online (Sandbox Code Playgroud)

将文件从资源中的目录 foo 复制到当前路径非常简单

(io/copy (io/file (io/resource "foo/test.txt")) (io/file "test.txt"))
Run Code Online (Sandbox Code Playgroud)

将两者结合起来,您应该能够编写一个满足您要求的递归函数

  • 不幸的是,这就是重点:您不能在正在运行的 jar 内的文件上使用 io/copy (尽管在 repl 内工作或与 lein run 一起工作),因为 jar 中的资源文件不处于“文件”状态(因此如果在 jar 内的“文件”上使用 io/file 将抛出“IllegalArgumentException:不是文件”)。它与 lein run 和 REPL 一起使用,因为资源文件不是从 jar 内部调用的,而是直接从文件系统调用的,因此它处于兼容的文件状态。 (3认同)