【问题标题】:Resources in Clojure applicationsClojure 应用程序中的资源
【发布时间】:2011-12-22 00:42:16
【问题描述】:

我在我的 Clojure 项目(一个 GUI 应用程序)中使用 Leiningen,并在项目根目录下创建了一个“资源”目录来保存我的应用程序使用的图像。

当我在测试期间在本地运行我的应用程序时,我使用相对路径“resources/logo.png”获取图像,这很好用。但是当我使用 Leiningen 构建 uberjar 时,Leiningen 将资源文件夹中的文件放在 JAR 的根文件夹中,因此我对资源文件的引用不再起作用。

使用 Leiningen 访问此类资源的正确方法是什么?

【问题讨论】:

  • 检查我的答案。我遇到了同样的问题。
  • 有没有很好的资源布局示例或使用它的示例项目?

标签: clojure leiningen


【解决方案1】:

前面的回答者(skuro)指出我需要从类路径中获取文件。经过多一点挖掘,这似乎是适用于我的情况的解决方案:

(.getFile (clojure.java.io/resource "foo.png"))

【讨论】:

  • (.getPath) 更准确,因为(.getFile) 还可能附加了资源 URL 中不应该存在的现有查询参数。
  • 对我来说还是不行。 (io/resource "file.png") 返回 nilfile.png 包含在 jar 文件中。所以我不确定发生了什么。 .getFile 只会导致 NPE,因此无法在其上使用 slurp
  • 找到了我的问题。我正在使用 ring 提供来自 resources/.../ 的目录,它在开发过程中工作。但是在我构建了jar 之后,ring.util.response/resource-response 中的验证失败了。因此它返回nil,因为它试图检查规范路径,但它不匹配,因为它在jar中。
【解决方案2】:

只是 Kevin Albrecht 答案的语法糖:

(require '[clojure.java.io :as io])

(-> "foo.png" io/resource io/file) 

【讨论】:

【解决方案3】:

这不是直接回答 OP 的问题,而是skuro mentioned something 在他的最后一段中非常有用,即在开发期间使资源在类路径上可用,但不将它们包含在发布 jar/uberjar 中。

这样做的原因是,您可以将资源单独放在 jar 之外 - 例如将配置文件放在 /etc 下 - 然后在运行时通过在类路径中列出此类资源文件夹来链接到它们。

project.clj 中的定义

  • 从您的 project.clj 中删除顶级 :resource-paths
  • 在顶层的 project.clj 中添加以下行:
:profiles {:dev {:resource-paths ["src/main/resources"]}}

这样,资源将在开发期间(编译、测试、复制)在类路径上可用,但不会包含在发布 jar 中。

作为一种选择,您可能希望将一些资源与发布 jar 捆绑在一起,例如应用程序图标和图形,而不是其他资源,例如配置文件。在这种情况下,您可以将资源文件夹拆分为子目录并声明您想要包含在顶层的那些,而其余的则在 dev 配置文件下:

:resource-paths ["src/main/resources/icons"
                 "src/main/resources/images"]
:profiles {:dev {:resource-paths ["src/main/resources/config"]}}

在代码中引用资源

使用上述方法,您可以通过在类路径(如KevinValerii 所示)而不是直接在文件系统上查看资源,在开发和生产期间统一引用资源:

(require '[clojure.java.io :as jio])
(jio/file (jio/resource "relative/path/to/resource.xml"))

运行时类路径

在开发期间,Leiningen 将在类路径中包含顶级资源和 dev 配置文件资源。对于发布的运行时,您必须自己为 JRE 配置类路径:

java -cp "/etc/myapp:/usr/local/lib/myapp.jar" myapp.core $*

此外,您实际上也可以将所有资源保留在 jar 中。这样,包含的资源将用作默认值。如果您设置类路径以使 .jar 文件位于配置文件夹之后(示例中为 /etc/myapp),则配置文件夹下具有相同相对资源路径的资源文件将优先于 jar 中包含的资源文件.

【讨论】:

    【解决方案4】:

    Leiningen 借鉴了 maven 的资源约定,文件夹布局略有不同。该规则规定resources 文件夹必须用作编译时类路径根目录,这意味着 leiningen 将所有文件放入 jar 内的根目录中的resources 文件夹中是正确的。

    问题在于物理位置 != 类路径位置,因此当您打包应用程序时前者会发生变化,而后者保持不变 (classpath:/)

    您最好依靠类路径位置来查找文件系统资源,或者将它们从 jar 中取出并将它们放入可预测的文件夹中,无论是静态的还是可配置的。

    【讨论】:

      【解决方案5】:

      我遇到了完全相同的问题,解决方案是使用io/file。例如,这是我的应用程序中的工作代码:

      (defn load-md [md]
        (->
         md
         io/resource ;;clojure.java.io
         slurp
         mp
         to-hiccup
         html))
      

      【讨论】:

        【解决方案6】:

        这样做的好方法。请注意,io/file 返回一个 java File 对象,然后可以将其传递给 slurp 等:

        (ns rescue.core
          (:require [clojure.java.io :as io] ))
        
        (def data-file (io/file
                         (io/resource 
                           "hello.txt" )))
        (defn -main []
          (println (slurp data-file)) )
        

        如果您随后在 lein 项目目录中执行以下操作:

        > echo "Hello Resources!" > resources/hello.txt
        > lein run
        Hello Resources!
        

        马上!您正在通过类路径读取资源文件。

        【讨论】:

          【解决方案7】:

          改变

          (.getPath (io/resource "file")) 
          

          到->

          (str (io/resource "file"))
          

          使它适用于我的情况,因为 strfile:/....path.... 添加到路径中。

          【讨论】:

            【解决方案8】:

            在我们的例子中,使用 .getPath.getFile 没有帮助。只需使用input-stream 即可解决。

            (require '[clojure.java.io :as io])
            
            (defonce classifier
              (-> "machine_learning/classifier.model"
                  io/resource
                  io/input-stream
                  helper/read))
            

            【讨论】:

            • 请更具体。您的意思可能是clojure.java.io/resource,但resource 可以是任何东西。 input-stream 也是如此。而helper/read 根本没有定义...
            • @mzuther 抱歉,我假设使用了 clojure.java.io,现在明确指出。你是对的,助手/阅读可以是任何东西;您想使用资源的任何功能。
            • @Brad_Koch 谢谢!我喜欢自己的答案,不需要太多的交叉阅读。 :)
            猜你喜欢
            • 2011-01-03
            • 2017-12-03
            • 2010-10-16
            • 2016-12-04
            • 2012-06-09
            • 2012-07-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多