J'aimerais connaître la manière "recommandée" de lire et d'écrire un fichier dans clojure 1.3 .
- Comment lire le fichier entier
- Comment lire un fichier ligne par ligne
- Comment écrire un nouveau fichier
- Comment ajouter une ligne à un fichier existant
J'aimerais connaître la manière "recommandée" de lire et d'écrire un fichier dans clojure 1.3 .
En supposant que nous ne faisons que des fichiers texte ici et pas des trucs binaires fous.
Numéro 1 : comment lire un fichier entier en mémoire.
(slurp "/tmp/test.txt")
Non recommandé lorsqu'il s'agit d'un très gros fichier.
Numéro 2 : comment lire un fichier ligne par ligne.
(use 'clojure.java.io)
(with-open [rdr (reader "/tmp/test.txt")]
(doseq [line (line-seq rdr)]
(println line)))
El with-open
La macro veille à ce que le lecteur soit fermé à la fin du corps. La fonction de lecture convertit une chaîne de caractères (elle peut aussi faire une URL, etc.) en un fichier de type BufferedReader
. line-seq
délivre un seq. paresseux. La demande de l'élément suivant de la séquence paresseuse entraîne la lecture d'une ligne dans le lecteur.
Notez qu'à partir de Clojure 1.7, vous pouvez également utiliser transducteurs pour la lecture des fichiers texte.
Numéro 3 : comment écrire dans un nouveau fichier.
(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
(.write wrtr "Line to be written"))
Encore une fois, with-open
veille à ce que le BufferedWriter
est fermé à l'extrémité du corps. Le rédacteur contraint une chaîne de caractères dans un BufferedWriter
que vous utilisez via java interop : (.write wrtr "something").
Vous pouvez également utiliser spit
le contraire de slurp
:
(spit "/tmp/test.txt" "Line to be written")
Numéro 4 : ajouter une ligne à un fichier existant.
(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt" :append true)]
(.write wrtr "Line to be appended"))
Idem que ci-dessus, mais maintenant avec l'option "append".
Ou encore avec spit
le contraire de slurp
:
(spit "/tmp/test.txt" "Line to be written" :append true)
PS : Pour être plus explicite sur le fait que vous lisez et écrivez dans un fichier et pas dans autre chose, vous pourriez d'abord créer un objet File et ensuite le contraindre dans un objet BufferedReader
ou Rédacteur :
(reader (file "/tmp/test.txt"))
;; or
(writer (file "tmp/test.txt"))
La fonction fichier se trouve également dans clojure.java.io.
PS2 : Il est parfois pratique de pouvoir voir quel est le répertoire courant (donc "."). Vous pouvez obtenir le chemin absolu de deux manières :
(System/getProperty "user.dir")
ou
(-> (java.io.File. ".") .getAbsolutePath)
Merci beaucoup pour votre réponse détaillée. Je suis heureux de connaître la méthode recommandée pour l'entrée de fichier (fichier texte) dans la version 1.3. Il semble qu'il y ait eu quelques bibliothèques sur les entrées-sorties de fichiers (clojure.contrb.io, clojure.contrib.duck-streams et quelques exemples utilisant directement le BufferedReader FileInputStream InputStreamReader de Java) qui m'ont rendu plus confus. De plus, il y a peu d'informations sur Clojure 1.3, surtout en japonais (ma langue naturelle) Merci.
Salut jolly-san, tnx pour accepter ma réponse ! Pour votre information, clojure.contrib.duck-streams est maintenant déprécié. Cela ajoute peut-être à la confusion.
C'est-à-dire, (with-open [rdr (reader "/tmp/test.txt")] (line-seq rdr))
donne IOException Stream closed
au lieu d'une collection de lignes. Que faire ? J'obtiens de bons résultats avec la réponse de @satyagraha, cependant.
Si le fichier tient dans la mémoire, vous pouvez le lire et l'écrire sans problème :
(def s (slurp "filename.txt"))
(s contient maintenant le contenu d'un fichier sous forme de chaîne)
(spit "newfile.txt" s)
Cela crée newfile.txt s'il ne se termine pas et écrit le contenu du fichier. Si vous voulez ajouter des données au fichier, vous pouvez faire ce qui suit
(spit "filename.txt" s :append true)
Pour lire ou écrire un fichier de manière linéaire, il faut utiliser le lecteur et l'écrivain de Java. Ils sont enveloppés dans l'espace de noms clojure.java.io :
(ns file.test
(:require [clojure.java.io :as io]))
(let [wrtr (io/writer "test.txt")]
(.write wrtr "hello, world!\n")
(.close wrtr))
(let [wrtr (io/writer "test.txt" :append true)]
(.write wrtr "hello again!")
(.close wrtr))
(let [rdr (io/reader "test.txt")]
(println (.readLine rdr))
(println (.readLine rdr)))
; "hello, world!"
; "hello again!"
Notez que la différence entre slurp/spit et les exemples de reader/writer est que le fichier reste ouvert (dans les instructions let) dans ces derniers et que la lecture et l'écriture sont mises en mémoire tampon, ce qui est plus efficace lors de lectures/écritures répétées dans un fichier.
Voici de plus amples informations : slurp cracher clojure.java.io Le lecteur tampon de Java L'écrivain de Java
Merci Paul. J'ai pu en apprendre davantage grâce à vos codes et à vos commentaires qui sont clairs et ciblés pour répondre à ma question. Merci beaucoup.
Merci d'avoir ajouté des informations sur les méthodes de niveau légèrement inférieur qui ne sont pas données dans la (excellente) réponse de Michiel Borkent sur les meilleures méthodes pour les cas typiques.
@Mars Merci. En fait, j'ai répondu à cette question en premier, mais la réponse de Michiel est plus structurée et semble être très populaire.
En ce qui concerne la question 2, on souhaite parfois que le flux de lignes soit renvoyé comme un objet de première classe. Pour obtenir cela comme une séquence paresseuse, tout en ayant le fichier fermé automatiquement sur EOF, j'ai utilisé cette fonction :
(use 'clojure.java.io)
(defn read-lines [filename]
(let [rdr (reader filename)]
(defn read-next-line []
(if-let [line (.readLine rdr)]
(cons line (lazy-seq (read-next-line)))
(.close rdr)))
(lazy-seq (read-next-line)))
)
(defn echo-file []
(doseq [line (read-lines "myfile.txt")]
(println line)))
Je ne pense pas que la nidification defn
est un Clojure idéomatique. Votre read-next-line
d'après ce que j'ai compris, est visible en dehors de vos read-lines
fonction. Vous avez peut-être utilisé une (let [read-next-line (fn [] ...))
à la place.
Pour lire un fichier ligne par ligne, il n'est plus nécessaire de recourir à l'interopérabilité :
(->> "data.csv"
io/resource
io/reader
line-seq
(drop 1))
Cela suppose que votre fichier de données est conservé dans le répertoire des ressources et que la première ligne est une information d'en-tête qui peut être supprimée.
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.
2 votes
Premier résultat de Google : lethain.com/fr/reading-file-in-clojure
8 votes
Ce résultat date de 2009, certaines choses ont été modifiées dernièrement.
12 votes
En effet. Cette question de StackOverflow est maintenant le premier résultat sur Google.