57

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

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

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

4

8 回答 8

52

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

(.getFile (clojure.java.io/resource "foo.png"))
于 2011-11-04T14:17:49.537 回答
32

只是 Kevin Albrecht 答案的语法糖:

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

(-> "foo.png" io/resource io/file) 
于 2013-06-02T07:36:40.890 回答
21

这不是直接回答 OP 的问题,但skuro在他的最后一段中提到了一些非常有用的东西,即在开发期间在类路径上提供资源,但不将它们包含在发布 jar/uberjar 中。

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

project.clj 中的定义

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

这样,资源将在开发期间(编译、测试、repl)在类路径上可用,但不会包含在发布 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 中包含的资源文件。

于 2014-06-13T15:26:31.103 回答
16

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

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

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

于 2011-11-04T13:28:32.503 回答
6

我有完全相同的问题,解决方案根本没有使用io/file。因此,例如,这是我的应用程序中的工作代码:

(defn load-md [md]
  (->
   md
   io/resource ;;clojure.java.io
   slurp
   mp
   to-hiccup
   html))
于 2015-03-19T22:44:42.717 回答
3

这样做的好方法。请注意,它io/file返回一个 javaFile对象,然后可以将其传递给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!

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

于 2014-05-01T22:35:46.917 回答
2

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

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

(defonce classifier
  (-> "machine_learning/classifier.model"
      io/resource
      io/input-stream
      helper/read))
于 2015-01-20T18:01:51.047 回答
2

从改变

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

到->

(str (io/resource "file"))

使它在我的情况下工作,str增加file:/....path....了路径。

于 2020-03-04T09:26:07.303 回答