В Clojure 1.3, Как читать и писать файл

Я хотел бы узнать "рекомендуемый" способ чтения и записи файла в clojure 1.3.

  • Как прочитать весь файл
  • Как читать файл по строкам
  • Как написать новый файл
  • Как добавить строку в существующий файл

Ответ 1

Предполагая, что мы делаем здесь только текстовые файлы, а не какие-то сумасшедшие бинарные файлы.

Номер 1: как прочитать весь файл в памяти.

(slurp "/tmp/test.txt")

Не рекомендуется, когда это действительно большой файл.

Номер 2: как читать файл по строкам.

(use 'clojure.java.io)
(with-open [rdr (reader "/tmp/test.txt")]
  (doseq [line (line-seq rdr)]
    (println line)))

Макрос with-open заботится о том, чтобы читатель был закрыт в конце тела. Функция читателя принуждает строку (она также может использовать URL и т.д.) В BufferedReader. line-seq обеспечивает ленивый сегмент. Требование следующего элемента ленивых результатов seq в строку, считываемую от читателя.

Обратите внимание, что начиная с Clojure 1.7, вы также можете использовать преобразователи для чтения текстовых файлов.

Номер 3: как записать в новый файл.

(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
  (.write wrtr "Line to be written"))

Опять же, with-open позаботится о том, чтобы BufferedWriter был закрыт в конце тела. Writer принуждает строку к BufferedWriter, которую вы используете с помощью java interop: (.write wrtr "something").

Вы также можете использовать spit, противоположный slurp:

(spit "/tmp/test.txt" "Line to be written")

Номер 4: добавьте строку в существующий файл.

(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt" :append true)]
  (.write wrtr "Line to be appended"))

То же, что и выше, но теперь с возможностью добавления.

Или снова с spit, напротив slurp:

(spit "/tmp/test.txt" "Line to be written" :append true)

PS: Чтобы более подробно рассказывать о том, что вы читаете и записываете в файл, а не что-то еще, вы можете сначала создать объект File, а затем принудительно вставить его в BufferedReader или Автор:

(reader (file "/tmp/test.txt"))
;; or
(writer (file "tmp/test.txt"))

Функция файла также находится в clojure.java.io.

PS2: Иногда бывает удобно видеть, что такое текущий каталог (так "." ). Вы можете получить абсолютный путь двумя способами:

(System/getProperty "user.dir") 

или

(-> (java.io.File. ".") .getAbsolutePath)

Ответ 2

Если файл вписывается в память, вы можете читать и писать его с помощью slurp и spit:

(def s (slurp "filename.txt"))

(s теперь содержит содержимое файла в виде строки)

(spit "newfile.txt" s)

Это создает файл newfile.txt, если он не выходит и не записывает содержимое файла. Если вы хотите добавить в файл, вы можете сделать

(spit "filename.txt" s :append true)

Чтобы прочитать или записать файл, вы должны использовать Java-читатель и писатель. Они заключены в пространство имен 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!"

Обратите внимание, что разница между slurp/spit и примерами чтения/записи заключается в том, что файл остается открытым (в операторах let) в последнем, а чтение и запись буферизируются, что более эффективно при многократном чтении/записи в файл.

Вот дополнительная информация: slurp spit  clojure.java.io Java BufferedReader Java Writer

Ответ 3

В отношении вопроса 2 иногда требуется, чтобы поток строк возвращался как объект первого класса. Чтобы получить это как ленивую последовательность и по-прежнему автоматически закрывать файл на EOF, я использовал эту функцию:

(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)))

Ответ 4

Это как прочитать весь файл.

Если файл находится в каталоге ресурсов, вы можете сделать это:

(let [file-content-str (slurp (clojure.java.io/resource "public/myfile.txt")])

не забудьте потребовать/использовать clojure.java.io.

Ответ 5

(require '[clojure.java.io :as io])
(io/copy (io/file "/etc/passwd") \*out*\)

Ответ 6

Чтобы читать файл построчно, вам больше не нужно прибегать к взаимодействию:

(->> "data.csv"
      io/resource
      io/reader
      line-seq
      (drop 1))

Это предполагает, что ваш файл данных хранится в каталоге ресурсов, а первая строка содержит информацию заголовка, которую можно отбросить.