W Clojure 1.3, Jak czytać i pisać plik

Chciałbym poznać "zalecany" sposób odczytu i zapisu pliku w clojure 1.3 .

  1. Jak odczytać cały plik
  2. Jak odczytać plik linia po linii
  3. Jak napisać nowy plik
  4. Jak dodać wiersz do istniejącego pliku
Author: Chris Martin, 2011-10-13

6 answers

Zakładając, że robimy tu tylko pliki tekstowe, a nie jakieś szalone binarne rzeczy.

Numer 1: Jak odczytać cały plik do pamięci.

(slurp "/tmp/test.txt")

Nie zaleca się, gdy jest to naprawdę duży plik.

Numer 2: Jak odczytać plik linia po linii.

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

Makro with-open dba o to, aby czytnik był zamknięty na końcu ciała. Funkcja reader wymusza ciąg znaków (może również wykonywać URL, itp.) do BufferedReader. line-seq dostarcza leniwego seq. Wymaganie kolejnego elementu leniwego seq skutkuje odczytaniem wiersza z czytnika.

Zauważ, że począwszy od Clojure 1.7, możesz również używać przetworników do odczytu plików tekstowych.

Numer 3: Jak napisać do nowego pliku.

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

Ponownie, with-open dba o to, aby BufferedWriter był zamknięty na końcu ciała. Writer wymusza ciąg znaków do BufferedWriter, którego używasz poprzez Java interop: (.write wrtr "something").

Można też użyć spit, przeciwieństwo slurp:

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

Numer 4: dołącza wiersz do istniejącego pliku.

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

To samo co wyżej, ale teraz z opcją Dołącz.

Lub ponownie z spit, przeciwieństwem slurp:

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

PS: aby być bardziej jednoznacznym o tym, że czytasz i piszesz do pliku, a nie czegoś innego, możesz najpierw utworzyć obiekt File, a następnie zmusić go do BufferedReader lub Writer:

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

Funkcja file jest również w clojure.java.io.

PS2: czasami jest to przydatne, aby móc zobaczyć, co bieżący katalog (tak "."). Można uzyskać ścieżkę absolutną na dwa sposoby:

(System/getProperty "user.dir") 

Lub

(-> (java.io.File. ".") .getAbsolutePath)
 261
Author: Michiel Borkent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-30 15:47:48

Jeśli plik mieści się w pamięci, możesz go odczytać i zapisać za pomocą slurp i spit:

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

(S zawiera teraz zawartość pliku jako łańcuch znaków)

(spit "newfile.txt" s)

To tworzy nowy plik.txt jeśli nie zakończy się i nie zapisze zawartości pliku. Jeśli chcesz dołączyć do pliku, możesz wykonać

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

Aby odczytać lub zapisać plik liniowo, należy użyć programu Reader i writer Javy. Są zawinięte w Przestrzeń nazw 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!"

Zauważ, że różnica między slurp/spit i przykładem programu reader/writer jest to, że plik pozostaje otwarty (w poleceniach let) w tym drugim, a odczyt i zapis jest buforowany, dzięki czemu jest bardziej wydajny przy wielokrotnym odczycie z / zapisie do pliku.

Oto więcej informacji: slurp spit clojure.java.io BufferedReader Javy Java ' S Writer

 30
Author: Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-13 16:43:16

Jeśli chodzi o pytanie 2, czasami chce się, aby strumień linii był zwracany jako obiekt pierwszej klasy. Aby uzyskać to jako leniwą sekwencję i nadal mieć plik zamknięty automatycznie na EOF, użyłem tej funkcji:

(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
Author: satyagraha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-10 13:52:51

Oto jak odczytać cały plik.

Jeśli plik znajduje się w katalogu zasobów, możesz to zrobić:

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

Pamiętaj, aby wymagać / używać clojure.java.io

 1
Author: joshua,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-23 16:56:54
(require '[clojure.java.io :as io])
(io/copy (io/file "/etc/passwd") \*out*\)
 0
Author: Dima Fomin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 10:40:57

Aby odczytać plik linia po linii, nie musisz już uciekać się do interop:

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

Zakłada to, że plik danych jest przechowywany w katalogu resources i że pierwsza linia To informacje nagłówka, które można odrzucić.

 0
Author: Chris Murphy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-05 16:19:06