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

时间:2015-02-21 11:51:23

标签: java jar clojure io copy

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

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

存在Java世界的几种解决方案(例如How to write a Java program which can extract a JAR file and store its data in specified directory (location)?How to extract directory (and sub directories) from jar resource?),但我没有找到任何现有的Clojure解决方案。 作为初学者(包括Clojure和Java),我不确定如何将上述解决方案转换为Clojure。逐字逐句地从Java翻译成Clojurish Java Interop看起来并不正确。 是否有"官方",clojure-idiomatic方式来做到这一点?

请注意,我使用的是Raynes' fs实用程序库。似乎没有直接这样做的功能,但是可能有一些我可以用来简化过程的元素? (除了明显的基本io糖)

4 个答案:

答案 0 :(得分:4)

几个月前我写了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)))

由于图书馆没有记住这个用例,因此有一些杂耍:

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

也许这对你有帮助。

答案 1 :(得分:0)

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

(defn list-resource
  [resource-dir]
  (let [resource (io/file (io/resource resource-dir))]
    (file-seq resource)))

将文件从资源中的目录foo复制到当前路径就像

一样简单
(io/copy (io/file (io/resource "foo/test.txt")) (io/file "test.txt"))

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

答案 2 :(得分:0)

在尝试了更多并从#clojure获得帮助之后,我能够想出一种"类似于clojurish-i-guess"从我之前的第一个链接翻译:

(ns my-ns
  (:require [me.raynes.fs    :as f])
  (:import [java.util.jar JarFile JarEntry]))

(defn extract-dir-from-jar
  "Takes the string path of a jar, a dir name inside that jar and a destination
  dir, and copies the from dir to the to dir."
  [^String jar-dir from to]
  (let [jar (JarFile. jar-dir)]
    (doseq [^JarEntry file (enumeration-seq (.entries jar))]
      (if (.startsWith (.getName file) from)
        (let [f (f/file to (.getName file))]
          (if (.isDirectory file)
            (f/mkdir f)
            (do (f/mkdirs (f/parent f))
                (with-open [is (.getInputStream jar file)
                            os (io/output-stream f)]
                  (io/copy is os)))))))))

我想我可以稍微整理一下(特别是在.startsWith位附近),但至少可以完美地运作。

答案 3 :(得分:0)

(defn copy-resource! [resource-filename]
  (let [resource-file (io/resource resource-filename)
        tmp-file (io/file "/tmp" resource-filename)]
    (with-open [in (io/input-stream resource-file)] (io/copy in tmp-file))))

(copy-resource! "my-logo.png")