【问题标题】:Clojure list subfolders in resources in uberjarClojure列出uberjar资源中的子文件夹
【发布时间】:2018-03-11 08:06:24
【问题描述】:

我有一个这样的文件夹结构:

  • 资源
    • 一个
      • b
        • x.txt
      • c
        • x.txt

我用lein uberjar 创建了我的可运行jar。

运行我的 jar 时,我想列出 a 的子文件夹。

我知道我可以使用 clojure.java.io 获取 resources/a/b/x.txt 的内容

(slurp (clojure.java.io/resource "a/b/x.txt"))

但我找不到列出子文件夹的简单方法。

(clojure.java.io/file (clojure.java.io/resource "a")) 只会生成java.lang.IllegalArgumentException: Not a file,因为它不是文件,而是 jar 文件中的资源。

有没有这样的图书馆?

【问题讨论】:

  • 这些都没有显示 1) 一种简单的方法来执行此操作 2) 执行此操作的库。我拒绝接受这个问题的答案是一大堆 Java 代码。
  • 嗯.. 将 java 代码转换为 clojure 是一项微不足道的任务。
  • 这可以通过 shell 中的单行来完成 (zipinfo -1 ...)。你需要用clojure代码来做吗?

标签: java file jar clojure


【解决方案1】:

这是来自 java 特定答案的代码端口:

(ns my-project.core
  (:require [clojure.string :as cs])
  (:import java.util.zip.ZipInputStream)
  (:gen-class))

(defrecord HELPER [])

(defn get-code-location []
  (when-let [src (.getCodeSource (.getProtectionDomain HELPER))]
    (.getLocation src)))

(defn list-zip-contents [zip-location]
  (with-open [zip-stream (ZipInputStream. (.openStream zip-location))]
    (loop [dirs []]
      (if-let [entry (.getNextEntry zip-stream)]
        (recur (conj dirs (.getName entry)))
        dirs))))

(defn -main [& args]
  (println (some->> (get-code-location)
                    list-zip-contents
                    (filter #(cs/starts-with? % "a/")))))

被放到主命名空间并使用jar运行将输出/resources/a文件夹中的所有路径..

java -jar ./target/my-project-0.1.0-SNAPSHOT-standalone.jar 
;;=> (a/ a/b/ a/b/222.txt a/222.txt)

还有一些快速研究将我带到了这个库: https://github.com/ronmamo/reflections

它缩短了代码,但也需要项目的一些依赖项(我想这可能是不可取的):

[org.reflections/reflections "0.9.11"]
[javax.servlet/servlet-api "2.5"]
[com.google.guava/guava "23.0"]

代码是这样的:

(ns my-project.core
  (:require [clojure.string :as cs])
  (:import java.util.zip.ZipInputStream
           [org.reflections
            Reflections
            scanners.ResourcesScanner
            scanners.Scanner
            util.ClasspathHelper
            util.ConfigurationBuilder])
  (:gen-class))

(defn -main [& args]
  (let [conf (doto (ConfigurationBuilder.)
               (.setScanners (into-array Scanner [(ResourcesScanner.)]))
               (.setUrls (ClasspathHelper/forClassLoader (make-array ClassLoader 0))))]
    (println
     (filter #(cs/starts-with? % "a/")
             (.getResources (Reflections. conf) #".*")))))

【讨论】:

  • 我已经接受了这个正确的答案——从技术上讲就是这样。解决方案的复杂性告诉我,我正在尝试完全做错事。
【解决方案2】:

另一种方法(但我必须承认它并不完全令人满意)是在编译时读取内容。假设您有一个函数 list-files 可以为您提供项目根目录中的列表:

(defmacro compile-time-filelist []
  `'~(list-files "resources/a"))

(defmacro compile-time-filelist []
  (vec (list-files "resources/a")))

【讨论】:

    【解决方案3】:

    您可以使用file-seq 函数递归地列出目录中的所有项目。示例:

    (let [files (file-seq (clojure.java.io/file "resources"))
          dir? #(.isDirectory %)]
      (map dir? files))
    

    您还可以在 File 对象上调用 .listFiles.list。第一个给出文件对象,第二个给出文件名。

    您可以找到更多示例 herehere

    【讨论】:

      猜你喜欢
      • 2015-11-20
      • 2018-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-18
      • 2018-03-13
      • 2013-05-10
      • 1970-01-01
      相关资源
      最近更新 更多