33 votes

chargement du fichier de configuration dans clojure en tant que structure de données

Est-il un lecteur de fonction en clojure pour analyser clojure structure de données? Mon cas d'utilisation est de lire la configuration des fichiers de propriétés et une valeur pour une propriété doit être une liste. J'aimerais être capable d'écrire ce que:

fichier.propriétés:

property1 = ["value1" "value2"]

et en clojure:

(load-props "file.properties")

et obtenir une carte avec la valeur {propriété1, ["valeur1" "valeur2"]

Maintenant,m je suis en train de faire la suite, avec le même fichier d'entrée "du fichier.les propriétés":

(defn load-props [filename]
    (let [io (java.io.FileInputStream. filename)
        prop (java.util.Properties.)]
    (.load prop io)
    (into {} prop)))

;; returns:
;; {"property1" "[\"valu1\", \"valu2\"]"}
(load-props "file.properties")

Mais je ne peux pas obtenir un moyen d'analyser le résultat d'un clojure du vecteur. Je suis fondamentalement à la recherche de quelque chose comme Erlang du fichier:consulter/1 fonction. Une idée de comment faire cela?

41voto

Korny Points 801

Si vous voulez lire java-les propriétés de style des fichiers, regardez Dave Ray réponse - si des fichiers de propriétés présentent de nombreuses limites.

Si vous utilisez Clojure 1.5 ou plus tard, je vous suggère d'utiliser de l'edn, les données extensible notation utilisée dans Datomic - c'est fondamentalement clojure structures de données, sans l'exécution de code arbitraire, et la possibilité d'ajouter des balises pour des choses comme des instances ou des types arbitraires.

La façon la plus simple d'utilisation, il est par la lecture de la chaîne et slurp:

(require 'clojure.edn)
(clojure.edn/read-string (slurp "filename.edn"))

C'est tout. Notez que la lecture de la chaîne ne lit que d'une seule variable, de sorte que vous devez définir votre configuration sur une carte:

{ :property1 ["value1" "value2"] }

Alors:

(require 'clojure.edn)
(def config (clojure.edn/read-string (slurp "config.edn")))
(println (:property1 config))

retourne

["value1" "value2"]

31voto

Dave Ray Points 20873

java.util.Properties implémente Map afin que cela puisse être fait très facilement sans analyser manuellement les fichiers de propriétés:

 (require 'clojure.java.io)
(defn load-props
  [file-name]
  (with-open [^java.io.Reader reader (clojure.java.io/reader file-name)] 
    (let [props (java.util.Properties.)]
      (.load props reader)
      (into {} (for [[k v] props] [(keyword k) (read-string v)])))))

(load-props "test.properties")
;=> {:property3 {:foo 100, :bar :test}, :property2 99.9, :property1 ["foo" "bar"]}
 

En particulier, les fichiers de propriétés sont plus compliqués que vous ne le pensez (commentaires, échappements, etc., etc.) et java.util.Properties est très bon pour les charger.

25voto

Jonas Points 8296

Est-il un lecteur de fonction en clojure pour analyser clojure structure de données?

Oui. Il s'appelle read. Vous pouvez également l'utiliser pour lire les données de configuration.

Un fichier props.clj contenant

{:property1 ["value1" 2]
 :property2 {:some "key"}}

peut être lu comme ceci:

(ns somens.core
  (:require [clojure.java.io :as io])
  (:import [java.io PushbackReader]))

(def conf (with-open [r (io/reader "props.clj")]
            (read (PushbackReader. r))))

Lors de la lecture de sources non fiables, il pourrait être une bonne idée au tour de *read-eval*:

(def conf (binding [*read-eval* false]
            (with-open [r (io/reader "props.clj")]
              (read (PushbackReader. r)))))

Pour l'écriture de la configuration des données dans un fichier que vous devriez regarder lors de l'impression des fonctions telles que pr et les amis.

3voto

Hamza Yerlikaya Points 21240

contrib a des fonctions pour lire les propriétés d'écriture,

http://richhickey.github.com/clojure-contrib/java-utils-api.html#clojure.contrib.java-utils/as-properties

Si c'est pour votre propre consommation, je suggère de lire / écrire des structures de données clojure, vous pouvez simplement les imprimer sur le disque et les lire.

0voto

BLUEPIXY Points 18514
 (use '[clojure.contrib.duck-streams :only (read-lines)])
(import '(java.io StringReader PushbackReader))

(defn propline->map [line] ;;property1 = ["value1" "value2"] -> { :property1  ["value1" "value2"] }
  (let [[key-str value-str] (seq (.split line "="))
        key (keyword (.trim key-str))
        value (read (PushbackReader. (StringReader. value-str)))]
        { key value } ))

(defn load-props [filename]
  (reduce into (map propline->map (read-lines filename))))
 

DEMO

 user=> (def prop (load-props "file.properties"))
#'user/prop
user=> (prop :property1)
["value1" "value2"]
user=> ((prop :property1) 1)
"value2"
 

MISE À JOUR

 (defn non-blank?   [line] (if (re-find #"\S" line) true false))
(defn non-comment? [line] (if (re-find #"^\s*\#" line) false true))

(defn load-props [filename]
  (reduce into (map propline->map (filter #(and (non-blank? %)(non-comment? %)) (read-lines filename)))))
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X