webentwicklung-frage-antwort-db.com.de

In Clojure 1.3 lesen und schreiben einer Datei

Ich würde gerne wissen, wie "empfehlenswert" ist, eine Datei in clojure 1.3 zu lesen und zu schreiben.

  1. Wie liest man die ganze Datei?
  2. So lesen Sie eine Datei Zeile für Zeile
  3. Wie schreibe ich eine neue Datei?
  4. So fügen Sie einer vorhandenen Datei eine Zeile hinzu
157
jolly-san

Angenommen, wir machen hier nur Textdateien und keine verrückten Binärsachen.

Nummer 1: Wie wird eine gesamte Datei in den Speicher eingelesen?

(Slurp "/tmp/test.txt")

Nicht zu empfehlen, wenn es sich um eine wirklich große Datei handelt.

Number 2: wie man eine Datei zeilenweise liest.

(use 'clojure.Java.io)
(with-open [rdr (reader "/tmp/test.txt")]
  (doseq [line (line-seq rdr)]
    (println line)))

Das with-open-Makro sorgt dafür, dass der Leser am Ende des Körpers geschlossen wird. Die Leserfunktion erzwingt eine Zeichenfolge (sie kann auch eine URL usw.) in eine BufferedReader. line-seq liefert eine faule Sequenz. Das Abfragen des nächsten Elements des Lazy-Seq führt dazu, dass eine Zeile vom Leser gelesen wird.

Beachten Sie, dass Sie ab Clojure 1.7 auch Transducer zum Lesen von Textdateien verwenden können.

Nummer 3: Wie schreibe ich in eine neue Datei?

(use 'clojure.Java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
  (.write wrtr "Line to be written"))

with-open sorgt wieder dafür, dass die BufferedWriter am Körperende geschlossen wird. Der Writer erzwingt einen String in eine BufferedWriter, die Sie über Java-Interop verwenden: (.write wrtr "something").

Sie können auch spit verwenden, das Gegenteil von Slurp:

(spit "/tmp/test.txt" "Line to be written")

Nummer 4: Eine Zeile an eine vorhandene Datei anhängen.

(use 'clojure.Java.io)
(with-open [wrtr (writer "/tmp/test.txt" :append true)]
  (.write wrtr "Line to be appended"))

Wie oben, aber jetzt mit Anhängeoption.

Oder noch einmal mit spit, dem Gegenteil von Slurp:

(spit "/tmp/test.txt" "Line to be written" :append true)

PS: Um genauer zu sagen, dass Sie eine Datei lesen und in eine Datei schreiben und nicht auf etwas anderes, können Sie zuerst ein Dateiobjekt erstellen und es dann in eine BufferedReader oder einen Writer zwingen:

(reader (file "/tmp/test.txt"))
;; or
(writer (file "tmp/test.txt"))

Die Dateifunktion befindet sich auch in clojure.Java.io.

PS2: Manchmal ist es praktisch, zu sehen, was das aktuelle Verzeichnis (also ".") Ist. Sie können den absoluten Pfad auf zwei Arten ermitteln:

(System/getProperty "user.dir") 

oder 

(-> (Java.io.File. ".") .getAbsolutePath)
262
Michiel Borkent

Wenn die Datei in den Speicher passt, können Sie sie mit Slurp lesen und schreiben:

(def s (Slurp "filename.txt"))

(s enthält jetzt den Inhalt einer Datei als Zeichenfolge)

(spit "newfile.txt" s)

Dadurch wird newfile.txt erstellt, wenn es nicht beendet wird, und der Dateiinhalt wird geschrieben. Wenn Sie an die Datei anhängen möchten, können Sie dies tun 

(spit "filename.txt" s :append true)

Um eine Datei zeilenweise zu lesen oder zu schreiben, würden Sie Javas Lese- und Schreibgerät verwenden. Sie sind im Namespace clojure.Java.io eingeschlossen:

(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!"

Beachten Sie, dass der Unterschied zwischen Slurp/spit und den Lese/Schreib-Beispielen darin besteht, dass die Datei in den let-Anweisungen in den letzteren geöffnet bleibt und das Lesen und Schreiben zwischengespeichert wird. Dies ist effizienter, wenn Sie wiederholt aus einer Datei lesen/in sie schreiben.

Hier finden Sie weitere Informationen: SlurpSpitclojure.Java.ioJavas BufferedReaderJavas Writer

31
Paul

In Frage 2 möchte man manchmal, dass der Zeilenstrom als erstklassiges Objekt zurückgegeben wird. Um dies als Lazy-Sequenz zu erhalten und die Datei immer noch automatisch in EOF zu schließen, habe ich diese Funktion verwendet:

(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)))
6
satyagraha

So lesen Sie die gesamte Datei.

Wenn sich die Datei im Ressourcenverzeichnis befindet, können Sie Folgendes tun:

(let [file-content-str (Slurp (clojure.Java.io/resource "public/myfile.txt")])

denken Sie daran, clojure.Java.io zu verwenden 

1
joshua
(require '[clojure.Java.io :as io])
(io/copy (io/file "/etc/passwd") \*out*\)
0
Dima Fomin

Um eine Datei Zeile für Zeile zu lesen, müssen Sie nicht mehr auf Interop zugreifen:

(->> "data.csv"
      io/resource
      io/reader
      line-seq
      (drop 1))

Dies setzt voraus, dass sich Ihre Datendatei im Ressourcenverzeichnis befindet und dass die erste Zeile Header-Informationen enthält, die verworfen werden können. 

0
Chris Murphy