web-dev-qa-db-ja.com

Clojureアプリケーションのリソース

私はClojureプロジェクト(GUIアプリケーション)でLeiningenを使用しており、プロジェクトルートの下に「resources」ディレクトリを作成して、アプリが使用する画像を保持しています。

テスト中にアプリをローカルで実行している場合、相対パス「resources/logo.png」を使用して画像を取得しますが、これは正常に機能します。しかし、Leiningenを使用してuberjarを作成すると、LeiningenはJARファイルのリソースフォルダーのファイルをJARのルートフォルダーに配置するため、リソースファイルへの参照は機能しなくなります。

ライニンゲンを使用してこのようなリソースにアクセスする正しい方法は何ですか?

52
Kevin Albrecht

前の回答者(skuro)は、クラスパスからファイルを取得する必要があると指摘しました。もう少し掘り下げた後、これは私の場合に有効な解決策のようです:

(.getFile (clojure.Java.io/resource "foo.png"))
46
Kevin Albrecht

Kevin Albrechtの答えに対する単なる構文糖:

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

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

これはOPの質問に直接答えているわけではありませんが、 skuro触れた 彼の最後の段落で非常に便利です。つまり、開発中にクラスパスでリソースを利用可能にしますが、リリースjar /ユーバージャー。

その理由は、たとえば/etcの下に構成ファイルを配置するなど、jarの外部にリソースを個別に配置し、そのようなリソースフォルダーをクラスパスにリストすることにより、実行時にそれらにリンクできるからです。

Project.cljの定義

  • project.cljからトップレベル:resource-pathsを削除します。
  • 最上位のproject.cljに次の行を追加します。
:profiles {:dev {:resource-paths ["src/main/resources"]}}

この方法では、開発中にクラスパスでリソースを使用できます(コンパイル、テスト、repl)が、リリースjarには含まれません。

代替として、アプリケーションアイコンやグラフィックスなどの一部のリソースをリリースjarにバンドルしたい場合がありますが、構成ファイルなどの他のリソースはバンドルしません。その場合、resourcesフォルダーをサブディレクトリーに分割し、トップレベルに含めるものを宣言し、残りをdevプロファイルの下に宣言します。

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

コードでリソースを参照する

上記の方法を使用すると、ファイルシステム上ではなく、クラスパス( Kevin および Valerii で示されているように)でリソースを検索することで、開発中と本番の両方でリソースを均一に参照できます:

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

ランタイムクラスパス

開発中、Leingingenはクラスパスにトップレベルとdevプロファイルリソースの両方を含めます。リリースされたランタイムの場合、JREのクラスパスを自分で設定する必要があります。

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

また、代わりに、実際にはすべてのリソースをjarに含めることができます。そうすることで、含まれているリソースがデフォルトとして使用されます。 .jarファイルが構成フォルダー(例では/etc/myapp)の後に来るようにクラスパスをセットアップすると、構成フォルダーの下にある同じ相対リソースパスを持つリソースファイルが、瓶。

14
Daniel Dinnyes

ライニンゲンは、フォルダのレイアウトがわずかに異なる、Mavenのリソースの規則を取り入れています。このルールは、resourcesフォルダーをコンパイル時のクラスパスルートとして使用する必要があることを示しています。つまり、leiningenはjar内のルートロケーションにあるresourcesフォルダー内のすべてのファイルを正しく配置します。

問題は、物理的な場所!=クラスパスの場所であるため、前者はアプリケーションをパッケージ化するときに変更されますが、後者は同じままです(classpath:/

クラスパスの場所に依存してファイルシステムリソースを見つけるか、jarからそれらを取り出して、予測可能なフォルダー(静的フォルダーまたは構成可能なフォルダー)に配置することをお勧めします。

14
skuro

私はまったく同じ問題を抱えていましたが、解決策はnotを使用してio/fileまったく。たとえば、これは私のアプリからの作業コードです:

(defn load-md [md]
  (->
   md
   io/resource ;;clojure.Java.io
   Slurp
   mp
   to-hiccup
   html))
4
Adam Arold

この例では、.getPathまたは.getFileは役に立たなかった。単にinput-stream代わりに解決しました。

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

それを行う良い方法。ご了承ください 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!

そしてプレスト!クラスパスを介してリソースファイルを読み取っています。

1
Alan Thompson