W Clojure 1.3, Jak czytać i pisać plik
Chciałbym poznać "zalecany" sposób odczytu i zapisu pliku w clojure 1.3 .
- Jak odczytać cały plik
- Jak odczytać plik linia po linii
- Jak napisać nowy plik
- Jak dodać wiersz do istniejącego pliku
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)
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
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)))
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
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*\)
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ć.
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