Ben clojure 1.3 bir dosya okuma ve yazma "önerilen" yolunu bilmek istiyorum.
- Tüm dosya nasıl okunur
- Dosya satır satır nasıl okunur
- Yeni bir dosya nasıl yazılır
- Varolan bir dosyaya satır nasıl eklenir
Ben clojure 1.3 bir dosya okuma ve yazma "önerilen" yolunu bilmek istiyorum.
Yanıtlar:
Burada sadece metin dosyaları yaptığımızı varsayarsak, çılgın ikili şeyler değil.
Sayı 1: bir dosyanın tamamını belleğe okuma.
(slurp "/tmp/test.txt")
Gerçekten büyük bir dosya olduğunda önerilmez.
Sayı 2: bir dosyayı satır satır okuma.
(use 'clojure.java.io)
(with-open [rdr (reader "/tmp/test.txt")]
(doseq [line (line-seq rdr)]
(println line)))
with-open
Makro okuyucu gövdenin ucunda kapalı olduğunu ilgilenir. Okuyucu işlevi, bir dizeyi (ayrıca bir URL vb. De yapabilir) a BufferedReader
. line-seq
tembel bir seq sağlar. Tembel seq'in bir sonraki elemanını talep etmek, okuyucudan okunan bir satırla sonuçlanır.
Clojure 1.7'den itibaren metin dosyalarını okumak için dönüştürücüler de kullanabileceğinizi unutmayın .
Sayı 3: Yeni bir dosyaya nasıl yazılır.
(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
(.write wrtr "Line to be written"))
Yine, vücudun sonunda kapalı with-open
olmasına dikkat eder BufferedWriter
. Yazar, bir dizeyi BufferedWriter
java birlikte çalışma yoluyla kullandığınız bir dizeye zorlar :(.write wrtr "something").
Ayrıca kullanabilirsiniz spit
, tam tersi slurp
:
(spit "/tmp/test.txt" "Line to be written")
Sayı 4: varolan bir dosyaya satır ekleyin.
(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt" :append true)]
(.write wrtr "Line to be appended"))
Yukarıdaki ile aynı, ancak şimdi ekleme seçeneği ile.
Veya yine spit
bunun tersi slurp
:
(spit "/tmp/test.txt" "Line to be written" :append true)
Not: Başka bir şey değil, bir Dosyaya okuduğunuz ve yazdığınız gerçeği hakkında daha açık olmak için, önce bir File nesnesi oluşturabilir ve daha sonra bunu bir BufferedReader
veya Yazar'a zorlayabilirsiniz:
(reader (file "/tmp/test.txt"))
;; or
(writer (file "tmp/test.txt"))
Dosya işlevi clojure.java.io dosyasında da bulunur.
PS2: Bazen geçerli dizinin (yani ".") Ne olduğunu görebilmek faydalı olabilir. Mutlak yolu iki şekilde elde edebilirsiniz:
(System/getProperty "user.dir")
veya
(-> (java.io.File. ".") .getAbsolutePath)
(with-open [rdr (reader "/tmp/test.txt")] (line-seq rdr))
verimler IOException Stream closed
. Ne yapalım? Yine de @satyagraha cevabı ile iyi sonuçlar alıyorum.
(with-open [rdr (reader "/tmp/test.txt")] (doall (line-seq rdr)))
doseq
getirilere dikkat edin nil
.
Dosya belleğe sığarsa, slurp ve spit ile okuyabilir ve yazabilirsiniz:
(def s (slurp "filename.txt"))
(s artık bir dosyanın içeriğini dize olarak içeriyor)
(spit "newfile.txt" s)
Bu, çıkmaz ve dosya içeriğini yazarsa newfile.txt dosyasını oluşturur. Eğer dosyaya eklemek istiyorsanız,
(spit "filename.txt" s :append true)
Bir dosyayı okumak veya yazmak için Java'nın okuyucusunu ve yazarını kullanırsınız. Bunlar clojure.java.io ad alanına sarılır:
(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!"
Slurp / spit ve okuyucu / yazar örnekleri arasındaki farkın, dosyanın ikincisinde açık kalmasına (let ifadelerinde) ve okuma ve yazmanın arabelleğe alındığına, bu nedenle bir dosyadan / dosyaya tekrar tekrar okunduğunda daha verimli olduğuna dikkat edin.
Daha fazla bilgi: slurp spit clojure.java.io Java'nın BufferedReader Java's Writer
Soru 2 ile ilgili olarak, bazen satır akışının birinci sınıf bir nesne olarak döndürülmesi gerekir. Bunu tembel bir dizi olarak almak ve hala dosyayı EOF üzerinde otomatik olarak kapatmak için bu işlevi kullandım:
(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)))
defn
ideomatik Clojure olduğunu düşünmüyorum . Sizin read-next-line
, bildiğim kadarıyla anlamak, dışında görünür olan read-lines
işlevi. Bunun (let [read-next-line (fn [] ...))
yerine bir tane kullanmış olabilirsiniz .
(require '[clojure.java.io :as io])
(io/copy (io/file "/etc/passwd") \*out*\)
Bir dosyayı satır satır okumak için artık birlikte çalışmaya başvurmanız gerekmez:
(->> "data.csv"
io/resource
io/reader
line-seq
(drop 1))
Bu, veri dosyanızın kaynaklar dizininde tutulduğunu ve ilk satırın atılabilecek başlık bilgileri olduğunu varsayar.