Saya ingin tahu cara "disarankan" membaca dan menulis file di clojure 1.3.
- Cara membaca seluruh file
- Cara membaca file baris demi baris
- Cara menulis file baru
- Cara menambahkan baris ke file yang ada
Saya ingin tahu cara "disarankan" membaca dan menulis file di clojure 1.3.
Jawaban:
Dengan asumsi kita hanya melakukan file teks di sini dan bukan beberapa hal biner gila.
Nomor 1: cara membaca seluruh file ke dalam memori.
(slurp "/tmp/test.txt")
Tidak disarankan saat ini adalah file yang sangat besar.
Nomor 2: cara membaca file baris demi baris.
(use 'clojure.java.io)
(with-open [rdr (reader "/tmp/test.txt")]
(doseq [line (line-seq rdr)]
(println line)))
The with-open
makro mengurus bahwa pembaca ditutup pada akhir tubuh. Fungsi pembaca memaksa sebuah string (itu juga dapat melakukan URL, dll) menjadi a BufferedReader
. line-seq
memberikan seq malas. Menuntut elemen berikutnya dari hasil malas menjadi baris yang sedang dibaca dari pembaca.
Perhatikan bahwa dari Clojure 1.7 dan selanjutnya, Anda juga dapat menggunakan transduser untuk membaca file teks.
Nomor 3: cara menulis ke file baru.
(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
(.write wrtr "Line to be written"))
Sekali lagi, with-open
berhati-hatilah agar BufferedWriter
ditutup di ujung tubuh. Writer memaksa string menjadi BufferedWriter
, yang Anda gunakan gunakan melalui java interop:(.write wrtr "something").
Anda juga bisa menggunakan spit
, kebalikan dari slurp
:
(spit "/tmp/test.txt" "Line to be written")
Nomor 4: tambahkan baris ke file yang ada.
(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt" :append true)]
(.write wrtr "Line to be appended"))
Sama seperti di atas, tetapi sekarang dengan opsi tambahkan.
Atau lagi dengan spit
, kebalikan dari slurp
:
(spit "/tmp/test.txt" "Line to be written" :append true)
PS: Untuk lebih eksplisit tentang fakta bahwa Anda membaca dan menulis ke File dan bukan sesuatu yang lain, Anda bisa membuat objek File terlebih dahulu dan kemudian memaksa menjadi BufferedReader
atau Penulis:
(reader (file "/tmp/test.txt"))
;; or
(writer (file "tmp/test.txt"))
Fungsi file juga di clojure.java.io.
PS2: Kadang-kadang berguna untuk dapat melihat apa direktori saat ini (jadi ".") Adalah. Anda bisa mendapatkan jalur absolut dengan dua cara:
(System/getProperty "user.dir")
atau
(-> (java.io.File. ".") .getAbsolutePath)
(with-open [rdr (reader "/tmp/test.txt")] (line-seq rdr))
menghasilkan IOException Stream closed
bukan kumpulan garis. Apa yang harus dilakukan? Saya mendapatkan hasil yang baik dengan jawaban oleh @ satyagraha.
(with-open [rdr (reader "/tmp/test.txt")] (doall (line-seq rdr)))
doseq
pengembalian nil
yang dapat menyebabkan waktu sedih-tidak-kembali-nilai.
Jika file tersebut sesuai dengan memori, Anda dapat membaca dan menulisnya dengan slurp dan meludah:
(def s (slurp "filename.txt"))
(sekarang berisi konten file sebagai string)
(spit "newfile.txt" s)
Ini menciptakan newfile.txt jika tidak keluar dan menulis konten file. Jika Anda ingin menambahkan file yang dapat Anda lakukan
(spit "filename.txt" s :append true)
Untuk membaca atau menulis file secara linier, Anda akan menggunakan pembaca dan penulis Java. Mereka dibungkus dalam namespace 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!"
Perhatikan bahwa perbedaan antara contoh slurp / spit dan pembaca / penulis adalah bahwa file tetap terbuka (dalam pernyataan let) di yang terakhir dan membaca dan menulis buffer, sehingga lebih efisien ketika berulang kali membaca dari / menulis ke file.
Berikut ini informasi lebih lanjut: slurp spit clojure.java.io Java BufferedReader Java's Writer
Mengenai pertanyaan 2, seseorang terkadang ingin aliran garis dikembalikan sebagai objek kelas satu. Untuk mendapatkan ini sebagai urutan malas, dan masih memiliki file ditutup secara otomatis pada EOF, saya menggunakan fungsi ini:
(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
adalah Clojure yang ideomatik. Anda read-next-line
, sejauh yang saya mengerti, terlihat di luar read-lines
fungsi Anda . Anda mungkin menggunakan yang (let [read-next-line (fn [] ...))
sebaliknya.
(require '[clojure.java.io :as io])
(io/copy (io/file "/etc/passwd") \*out*\)
Untuk membaca file baris demi baris, Anda tidak perlu lagi melakukan interop:
(->> "data.csv"
io/resource
io/reader
line-seq
(drop 1))
Ini mengasumsikan bahwa file data Anda disimpan di direktori sumber daya dan bahwa baris pertama adalah informasi header yang dapat dibuang.