Clojure应用程序中的资源

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

当我在testing期间在本地运行我的应用程序时,我使用相对path“resources / logo.png”来获取图像,并且工作正常。 但是当我使用Leiningen构build一个uberjar时,Leiningen把来自resources文件夹的文件放在JAR的根文件夹中,所以我对资源文件的引用不再工作。

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

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

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

只是一个语法糖的答案凯文·阿尔布雷希特:

 (require '[clojure.java.io :as io]) (-> "foo.png" io/resource io/file) 

Leiningen借用maven资源的约定,稍微不同的文件夹布局。 该规则指出resources文件夹必须用作编译时的classpath root,这意味着leiningen正确地将resources文件夹内的所有文件放在jar内的根位置。

问题是物理位置!= classpath位置,所以当你打包应用程序时,前者会改变,后者保持不变( classpath:/

你最好依靠classpath的位置来find你的文件系统资源,或者把它们从jar中拿出来放到一个可预测的文件夹里,不pipe是静态还是可configuration的。

这并不是直接回答OP的问题,但skuro在最后一段提到了一些相当有用的东西,即在开发过程中在类path中提供资源,但不包括在发布jar / uberjar中。

这样做的原因是你可以把资源分别放在jar外面 – 比如把configuration文件放在/etc下,然后在运行时通过在类path中列出这些资源文件夹链接到它们。

project.clj中的定义

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

这样在开发过程中(compile,test,repl)就可以在类path上获得这些资源,但是不会包含在发布jar包中。

作为候选者,您可能想要将一些资源与发行版jar捆绑在一起,例如应用程序图标和graphics,而不是其他configuration文件。 在这种情况下,您可以将资源文件夹拆分成子目录,并声明要包含在顶层的资源文件夹,其余部分位于devconfiguration文件中:

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

在代码中引用资源

使用上面的方法,您可以在开发和生产过程中均匀地引用资源,方法是在类path中查找它们(如Kevin和Valerii所示),而不是直接在文件系统上:

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

运行时类path

在开发过程中,Leiningen将在类path中包含顶级configuration文件和devconfiguration文件资源。 对于发布的运行时,您将必须自行configurationJRE的类path:

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

另外,或者你可以实际上留下jar子里的所有资源。 这样,包含的资源将被用作默认值。 如果设置类path以使.jar文件位于configuration文件夹(例如/etc/myapp )之后,那么configuration文件夹下具有相同相对资源path的资源文件将优先于包含在jar。

我有完全相同的问题,解决scheme根本使用io/file 。 所以,例如,这是我的应用程序的工作代码:

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

在我们的例子中,使用.getPath.getFile是无益的。 简单地使用input-stream而不是解决它。

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

很好的做法。 请注意, 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! 您正在通过类path读取资源文件。