【问题标题】:How to load program resources in Clojure如何在 Clojure 中加载程序资源
【发布时间】:2011-01-03 21:40:17
【问题描述】:

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

我尝试的第一件事是

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

但永远找不到资源。

你可以做类似的事情

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

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

您可以尝试将上下文类加载器与类似的东西一起使用

...

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

strem 始终为零。

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

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

任何帮助将不胜感激。

编辑:这是一个更具体的例子。在 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**"));
    }
}

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

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

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

【问题讨论】:

  • 你能在java中添加一个例子吗?
  • @arthur:在 Java 中添加了一个更具体的示例。你将如何在 Clojure 中完成同样的事情?

标签: java interop resources clojure markdown


【解决方案1】:
(clojure.java.io/resource "myscript.js")

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      是目录结构。

      继续 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**")))
      

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

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

      【讨论】:

        【解决方案4】:

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

        代码:

        (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.io.BufferedInputStream@1549f94

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

        【讨论】:

        • 是的,这可能在 REPL 中运行良好。但是有没有可能把它放在一个函数中,生成一个类,把编译好的类和资源一起放在一个 jar 中,运行 jar 中的类并让它成功加载资源?抱歉,如果我不清楚想要编译成一个类并构建一个 jar。英语只是我的第二语言。困惑是我的第一个 ;-)
        • 不知道为什么这被否决了,但我给它一个+1,因为输出确实让我了解了所需的目录结构。
        • 我也赞成这个方法,因为这两种方法对我都很有效(与此页面上的其他一些解决方案不同)
        猜你喜欢
        • 2011-12-22
        • 2015-11-20
        • 1970-01-01
        • 2011-05-18
        • 2014-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多