Clojure 应用程序中的资源
我在 Clojure 项目(一个 GUI 应用程序)中使用 Leiningen,并在项目根目录下创建了一个“资源”目录来保存我的应用程序使用的图像。
当我在测试期间在本地运行我的应用程序时,我使用相对路径“resources/logo.png”获取图像,这工作正常。但是,当我使用 Leiningen 构建 uberjar 时,Leiningen 会将资源文件夹中的文件放入 JAR 的根文件夹中,因此我对资源文件的引用不再起作用。
使用 Leiningen 访问此类资源的正确方法是什么?
I am using Leiningen in my Clojure project (a GUI application) and created a "resources" directory under the project root to hold images that my app uses.
When I am running my app locally during testing, I fetch the images using the relative path "resources/logo.png", and this works fine. But when I build an uberjar using Leiningen, Leiningen puts the files from the resources folder in the JAR's root folder, so my references to resource files don't work anymore.
What is the correct way to access resources like this using Leiningen?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
前面的回答者(skuro)指出我需要从类路径中获取文件。经过更多挖掘后,这似乎是适合我的情况的解决方案:
The previous answerer (skuro) pointed out that I need to get the file from the classpath. After a little more digging, this appears to be the solution that works for my case:
只是 Kevin Albrecht 答案的语法糖:
Just a syntax sugar for the answer of Kevin Albrecht:
这并没有直接回答OP的问题,但是skuro在他的最后一段中提到了一些东西,这可能非常有用,即开发期间类路径上可用的资源,但不将它们包含在发布 jar/uberjar 中。
原因是您可以将资源单独放置在 jar 之外 - 例如将配置文件放置在
/etc
下 - 然后在运行时通过在类路径上列出此类资源文件夹来链接到它们。project.clj 中的定义
:resource-paths
;这样,资源将在开发(编译、测试、repl)期间在类路径上可用,但不会包含在发布 jar 中。
作为替代方案,您可能希望将一些资源与发布 jar 捆绑在一起,例如应用程序图标和图形,但不捆绑其他资源,例如配置文件。在这种情况下,您可以将资源文件夹拆分为子目录,并声明您想要包含在顶层的子目录,而其余的则位于
dev
配置文件下:在代码中引用资源
使用上述方法,您可以在开发和生产过程中通过在类路径上查看统一参考资源(如 Kevin 和 Valerii),而不是直接在文件系统上:
运行时类路径
在开发期间 Leiningen 将包括顶层和
dev< /code> 配置文件类路径上的资源。对于发布的运行时,您必须自己配置 JRE 的类路径:
此外,您实际上也可以保留 jar 中包含的所有资源。这样,包含的资源将被用作默认值。如果您设置类路径,使 .jar 文件位于配置文件夹(示例中为
/etc/myapp
)之后,则配置文件夹下具有相同相对资源路径的资源文件将采用优先于 jar 中包含的内容。This is not directly answering the OP's question, but skuro mentioned something in his last paragraph which can be quite useful, i.e. to make resources available on the classpath during development, but not include them in the release jar/uberjar.
The reason of that is then you could place the resources separately outside of the jar – for example placing configuration files under
/etc
– and then link to them at runtime by listing such resource folders on the classpath.Definitions in project.clj
:resource-paths
from your project.clj;This way the resources will be available on the classpath during development (compile, test, repl), but will not be included in the release jars.
As an altenative, you might want to bundle some of the resources with the release jar, like application icons and graphics, but not others, like configuration files. In that case you could split the resources folder into subdirectories and declare the ones you want to get included at the top level, while the rest under the
dev
profile:Referencing resources in code
Using the above method you could reference resources both during development and production uniformly by looking them on the classpath (as shown by Kevin and Valerii), and not directly on the filesystem:
Runtime classpath
During development Leiningen would include both the top level and the
dev
profile resources on the classpath. For the released runtime you will have to configure the classpath for the JRE yourself:Also, alternatively you can in fact leave all the resources included in the jar. That way the included resources would be used as defaults. If you set up the classpath so that the .jar file comes after the configuration folder (
/etc/myapp
in the example), then the resource files with the same relative resource path under the configuration folder will take precedence over the ones included in the jar.Leiningen 借用了 Maven 的资源约定,但文件夹布局略有不同。该规则规定
resources
文件夹必须用作编译时类路径根,这意味着 leiningen 将所有文件放入resources
文件夹中的根位置是正确的。罐。问题在于物理位置!=类路径位置,因此当您打包应用程序时前者发生变化,而后者保持不变(
classpath:/
)您最好依靠类路径位置来查找您的文件系统资源,或者将它们从 jar 中取出并将它们放入可预测的文件夹中,无论是静态的还是可配置的。
Leiningen borrows the convention for resources from maven, with slightly different folder layouts. The rule states that the
resources
folder must be used as a compile time classpath root, meaning that leiningen is right in putting all the files insideresources
folder in the root location inside the jar.The problem is that physical location != classpath location, so that while the former changes when you package you application, the latter stays the same (
classpath:/
)You'd better rely on classpath location to find your file system resources, or take them out of the jar and place them into a predictable folder, either a static or a configurable one.
我遇到了完全相同的问题,解决方案是不使用
io/file
。例如,这是我的应用程序中的工作代码:I had the exact same problem and the solution is not using
io/file
at all. So for example this is working code from my app:这样做的好方法。请注意,
io/file
返回一个 javaFile
对象,然后可以将其传递给slurp
等:如果您随后在lein 项目目录:
很快!您正在通过类路径读取资源文件。
Nice way of doing it. Note that
io/file
returns a javaFile
object, which can then be passed toslurp
, etc:If you then execute the following in your lein project dir:
and presto! You are reading resource files via the classpath.
更改为
->
使它在我的情况下工作,因为
str
将file:/....path....
添加到路径。changing from
to ->
made it work in my case, as
str
addsfile:/....path....
to path.在我们的例子中,使用
.getPath
或.getFile
没有帮助。只需使用input-stream
即可解决它。In our case, using
.getPath
or.getFile
was unhelpful. Simply usinginput-stream
instead resolved it.