Tôi muốn biết cách "khuyến nghị" đọc và viết một tệp trong clojure 1.3.
- Cách đọc toàn bộ tập tin
- Cách đọc từng dòng tệp
- Cách viết một tập tin mới
- Cách thêm một dòng vào một tệp hiện có
Tôi muốn biết cách "khuyến nghị" đọc và viết một tệp trong clojure 1.3.
Câu trả lời:
Giả sử chúng ta chỉ làm các tệp văn bản ở đây và không phải là một số thứ nhị phân điên rồ.
Số 1: cách đọc toàn bộ tập tin vào bộ nhớ.
(slurp "/tmp/test.txt")
Không được đề xuất khi nó là một tập tin thực sự lớn.
Số 2: cách đọc một dòng tệp theo dòng.
(use 'clojure.java.io)
(with-open [rdr (reader "/tmp/test.txt")]
(doseq [line (line-seq rdr)]
(println line)))
Các with-open
vĩ mô chăm sóc mà người đọc được đóng cửa vào cuối của cơ thể. Hàm đọc buộc một chuỗi (nó cũng có thể tạo một URL, v.v.) thành một BufferedReader
. line-seq
cung cấp một seq lười biếng. Yêu cầu yếu tố tiếp theo của seq lười biếng dẫn đến một dòng được đọc từ người đọc.
Lưu ý rằng từ Clojure 1.7 trở đi, bạn cũng có thể sử dụng các bộ chuyển đổi để đọc tệp văn bản.
Số 3: làm thế nào để ghi vào một tập tin mới.
(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
(.write wrtr "Line to be written"))
Một lần nữa, hãy with-open
quan tâm rằng BufferedWriter
đóng cửa ở cuối cơ thể. Nhà văn đã ép buộc một chuỗi thành một BufferedWriter
, mà bạn sử dụng thông qua java interop:(.write wrtr "something").
Bạn cũng có thể sử dụng spit
, ngược lại slurp
:
(spit "/tmp/test.txt" "Line to be written")
Số 4: nối một dòng vào một tệp hiện có.
(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt" :append true)]
(.write wrtr "Line to be appended"))
Tương tự như trên, nhưng bây giờ với tùy chọn chắp thêm.
Hoặc một lần nữa với spit
, ngược lại với slurp
:
(spit "/tmp/test.txt" "Line to be written" :append true)
PS: Để rõ ràng hơn về thực tế là bạn đang đọc và ghi vào Tệp chứ không phải thứ gì khác, trước tiên bạn có thể tạo một đối tượng Tệp và sau đó ép buộc nó thành một BufferedReader
hoặc Trình ghi:
(reader (file "/tmp/test.txt"))
;; or
(writer (file "tmp/test.txt"))
Hàm tập tin cũng có trong clojure.java.io.
PS2: Đôi khi thật tiện dụng để có thể xem thư mục hiện tại (vì vậy ".") Là gì. Bạn có thể có được đường dẫn tuyệt đối theo hai cách:
(System/getProperty "user.dir")
hoặc là
(-> (java.io.File. ".") .getAbsolutePath)
(with-open [rdr (reader "/tmp/test.txt")] (line-seq rdr))
sản lượng IOException Stream closed
thay vì một bộ sưu tập các dòng. Phải làm sao Mặc dù nhận được kết quả tốt với câu trả lời của @satyagraha.
(with-open [rdr (reader "/tmp/test.txt")] (doall (line-seq rdr)))
doseq
lợi nhuận nil
có thể dẫn đến thời gian giá trị buồn-không trả lại.
Nếu tập tin vừa với bộ nhớ, bạn có thể đọc và ghi nó với tiếng lách cách và nhổ:
(def s (slurp "filename.txt"))
(s hiện chứa nội dung của tệp dưới dạng chuỗi)
(spit "newfile.txt" s)
Điều này tạo newfile.txt nếu nó không thoát và ghi nội dung tệp. Nếu bạn muốn thêm vào tập tin, bạn có thể làm
(spit "filename.txt" s :append true)
Để đọc hoặc viết một tệp theo chiều dọc, bạn sẽ sử dụng trình đọc và ghi của Java. Chúng được gói trong không gian tên 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!"
Lưu ý rằng sự khác biệt giữa slurp / spit và các ví dụ về trình đọc / ghi là tệp vẫn mở (trong các câu lệnh let) ở phần sau và việc đọc và viết được đệm, do đó hiệu quả hơn khi đọc / ghi nhiều lần vào tệp.
Dưới đây là thông tin thêm: slurp nhổ clojure.java.io Trình soạn thảo Java của BufferedReader Java
Về câu hỏi 2, đôi khi người ta muốn dòng dòng được trả về như một đối tượng hạng nhất. Để có được điều này như một chuỗi lười biếng và vẫn đóng tệp tự động trên EOF, tôi đã sử dụng chức năng này:
(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
là Clojure ý thức hệ. Theo read-next-line
như tôi hiểu, bạn có thể nhìn thấy bên ngoài read-lines
chức năng của bạn . Bạn có thể đã sử dụng một (let [read-next-line (fn [] ...))
thay thế.
(require '[clojure.java.io :as io])
(io/copy (io/file "/etc/passwd") \*out*\)
Để đọc một dòng tệp theo từng dòng, bạn không còn cần phải dùng đến interop:
(->> "data.csv"
io/resource
io/reader
line-seq
(drop 1))
Điều này giả định rằng tệp dữ liệu của bạn được lưu trong thư mục tài nguyên và dòng đầu tiên là thông tin tiêu đề có thể bị loại bỏ.