java 如何在Clojure中加载程序资源

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2044394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 19:06:43  来源:igfitidea点击:

How to load program resources in Clojure

javainteropresourcesclojuremarkdown

提问by clartaq

How do you load program resources such as icons, strings, graphical elements, scripts, and so on in a Clojure program? I am using a project layout similar to that in many Java projects where there is a "resources" directory hanging off of a "source" directory. A jar file is created from the source and includes the resources, but I can't seem to get the resources loaded as I would in Java.

如何在 Clojure 程序中加载程序资源,例如图标、字符串、图形元素、脚本等?我使用的项目布局类似于许多 Java 项目中的布局,其中有一个“资源”目录挂在“源”目录之外。从源代码创建了一个 jar 文件并包含资源,但我似乎无法像在 Java 中那样加载资源。

The first thing I tried was something like

我尝试的第一件事是

(ClassLoader/getSystemResource "resources/myscript.js")

But could never find the resource.

但是一直找不到资源。

You can do something similar with

你可以做类似的事情

...
  (let [cls (.getClass net.mydomain.somenamespace)
        strm (.getResourceAsStream cls name)        ]
...

where name is the nameof the resource to load, but the stream is nil.

其中 name 是name要加载的资源的 ,而流是nil

You can try using the context class loader with something like

您可以尝试使用上下文类加载器

...

(let [thr (Thread/currentThread)
      ldr (.getContextClassLoader thr)
      strem (.getResourceAsStream ldr name)]
...

But stremis always nil.

strem始终为零。

In frustration, I've tried placing the resource files in just about every directory in the program. They get copied into the jar correctly, but I still can't seem to load them.

令人沮丧的是,我尝试将资源文件放在程序中的几乎每个目录中。它们被正确复制到 jar 中,但我似乎仍然无法加载它们。

I've looked at the language sources for the loadfunction and the run-time library, but am not "getting" it.

我已经查看了load函数和运行时库的语言源,但我没有“理解”它。

Any help would be appreciated.

任何帮助,将不胜感激。

EDIT: Here's a more concrete example. In Java, if you wanted to convert MarkDown to HTML, you might use the showdown.jsscript and write something like:

编辑:这是一个更具体的例子。在 Java 中,如果您想将 MarkDown 转换为 HTML,您可以使用showdown.js脚本并编写如下内容:

package scriptingtest;

import java.io.InputStreamReader;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Example {

    private Object converter;

    public String transformMarkDown(String markdownString) {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("js");
        try {
            engine.eval(new InputStreamReader(getClass().getResourceAsStream(
                    "resources/showdown.js")));
            converter = engine.eval("new Showdown.converter()");
        } catch (Exception e) {
            return "Failed to create converter";
        }
        try {
            return ((Invocable) engine).invokeMethod(converter, "makeHtml",
                    markdownString).toString();
        } catch (Exception e) {
            return "Conversion failed";
        }
    }

    public static void main(String[] args) {
        System.out.println(new Example().transformMarkDown("plain, *emphasis*, **strong**"));
    }
}

when I create the project, it all gets compiled and packed into a jar. When run, the program outputs <p>plain, <em>emphasis</em>, <strong>strong</strong></p>

当我创建项目时,它都会被编译并打包到一个 jar 中。运行时,程序输出<p>plain, <em>emphasis</em>, <strong>strong</strong></p>

A literal translation to Clojure seems pretty straightforward, but I run into trouble trying to create the InputStreamReader-- I can't seem to write the code needed to find the script file in the jar.

Clojure 的字面翻译似乎很简单,但我在尝试创建时遇到了麻烦InputStreamReader——我似乎无法编写在 jar 中查找脚本文件所需的代码。

Edit: Added "markdown" tag since the post gives two complete examples of approaches to processing markdown.

编辑:添加了“降价”标签,因为该帖子提供了两个处理降价方法的完整示例。

采纳答案by clartaq

It's the directory structure.

这是目录结构。

Continuing with the scripting engine example in the OP, a Clojure equivalent would be:

继续 OP 中的脚本引擎示例,Clojure 等效项将是:

(ns com.domain.example
  (:gen-class)
  (:import (java.io InputStreamReader))
  (:import (javax.script ScriptEngineManager ScriptEngine)))

(defn load-resource
  [name]
  (let [rsc-name (str "com/domain/resources/" name)
        thr (Thread/currentThread)
        ldr (.getContextClassLoader thr)]
    (.getResourceAsStream ldr rsc-name)))

(defn markdown-to-html
  [mkdn]
  (let [manager (new ScriptEngineManager)
        engine (.getEngineByName manager "js")
        is (InputStreamReader. (load-resource "showdown.js"))
        _ (.eval engine is)
        cnv-arg (str "new Showdown.converter().makeHtml(\"" mkdn "\")")]
    (.eval engine cnv-arg)))

(defn -main
  []
  (println (markdown-to-html "plain, *emphasis*, **strong**")))

Note that the path to the resources is com/domain/resourcesfor this code as opposed to com/domain/scriptingtest/resourcesin the Java version. In the clojure version, the source file, example.cljis in com/domain. In the Java version, the source file, Example.javais in the com/domain/scriptingtestpackage.

请注意,资源的路径是com/domain/resources针对此代码的,而不是com/domain/scriptingtest/resources在 Java 版本中。在 clojure 版本中,源文件example.clj位于com/domain. 在 Java 版本中,源文件Example.javacom/domain/scriptingtest包中。

When setting up a project in my IDE, NetBeans, the Java project wizard asks for an enclosing package for the source. The Clojure plugin, enclojure, asks for a namespace, not a package. I had never noted that difference before. Hence the "off-by-one" error in the directory structure expected.

在我的 IDE NetBeans 中设置项目时,Java 项目向导要求提供源的封闭包。Clojure 插件 enclojure 要求命名空间,而不是包。我以前从未注意到这种差异。因此,在预期的目录结构中会出现“一对一”错误。

回答by Joe Snikeris

(clojure.java.io/resource "myscript.js")

回答by miaubiz

you can also use clojure.lang.RT/baseLoader

你也可以使用clojure.lang.RT/baseLoader

(defn serve-public-resource [path]
  (.getResourceAsStream (clojure.lang.RT/baseLoader) (str "public/" path))) 

回答by jsight

I placed the file in testpkg/test.txt (relative to current directory).

我将文件放在 testpkg/test.txt (相对于当前目录)。

Code:

代码:

(def x 5)
(def nm "testpkg/test.txt")
(def thr (Thread/currentThread))
(def ldr (.getContextClassLoader thr))
(def strem (.getResourceAsStream ldr nm))
(def strem2 (ClassLoader/getSystemResource nm))
(. System/out (println "First Approach:"))
(. System/out (println strem))
(. System/out (println))
(. System/out (println))
(. System/out (println "Second Approach:"))
(. System/out (println strem2))

$ java -cp .\;clojure.jar clojure.main test.clj

$ java -cp .\;clojure.jar clojure.main test.clj

First Approach: java.io.BufferedInputStream@1549f94

Second Approach: file:/C:/jsight/javadevtools/clojure-1.1.0/testpkg/test.txt

第一种方法:java.io.BufferedInputStream@1549f94

第二种方法:file:/C:/jsight/javadevtools/clojure-1.1.0/testpkg/test.txt