Clojure应用程序中的资源

时间:2011-11-04 13:22:24

标签: clojure leiningen

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

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

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

8 个答案:

答案 0 :(得分:46)

之前的回答者(skuro)指出我需要从类路径中获取文件。经过一番挖掘后,这似乎是适合我案例的解决方案:

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

答案 1 :(得分:30)

凯文阿尔布雷希特答案的语法糖:

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

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

答案 2 :(得分:14)

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

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

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

答案 3 :(得分:14)

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

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

project.clj中的定义

  • 从project.clj;
  • 中删除顶级:resource-paths
  • 在顶层的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)之后,则配置文件夹下具有相同相对资源路径的资源文件将优先于包含在其中的资源文件。罐子。

答案 4 :(得分:4)

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

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

答案 5 :(得分:2)

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

到->

(str (io/resource "file"))

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

答案 6 :(得分:1)

做得好的好方法。请注意,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!

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

答案 7 :(得分:1)

在我们的案例中,使用.getPath.getFile无益。只需使用input-stream代替解决它。

(defonce classifier
  (-> "machine_learning/classifier.model"
      resource
      input-stream
      helper/read))