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-openMakro okuyucu gövdenin ucunda kapalı olduğunu ilgilenir. Okuyucu işlevi, bir dizeyi (ayrıca bir URL vb. De yapabilir) a BufferedReader. line-seqtembel 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-openolmasına dikkat eder BufferedWriter. Yazar, bir dizeyi BufferedWriterjava 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 spitbunun 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 BufferedReaderveya 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)))
doseqgetirilere 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)))
defnideomatik Clojure olduğunu düşünmüyorum . Sizin read-next-line, bildiğim kadarıyla anlamak, dışında görünür olan read-linesiş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.