Files and I/O
Prerequisites: Error handling, Java interop
spit and slurp
(spit "notes.txt" "first line\n") ; write (replaces)
(spit "notes.txt" "second line\n" :append true)
(print (slurp "notes.txt"))
(println (count (clojure.string/split-lines (slurp "notes.txt"))))
first line
second line
2
spit writes a string to a file and slurp reads a whole file (or URL)
into a string — perfect for small files. Both use UTF-8 by default.
Reading large files line by line
(require '[clojure.java.io :as io]
'[clojure.string :as str])
(spit "scores.csv" "name,score\nada,91\nlinus,78\ngrace,88\n")
(with-open [rdr (io/reader "scores.csv")]
(let [rows (->> (line-seq rdr)
rest ; skip header
(map #(str/split % #","))
(map (fn [[name score]] {:name name :score (parse-long score)}))
doall)] ; realize before closing!
(doseq [{:keys [name score]} rows]
(println (format "%-6s %s" name (if (>= score 80) "pass+" "pass"))))
(println "best:" (:name (apply max-key :score rows)))))
ada pass+
linus pass
grace pass+
best: ada
with-openopens resources and closes them when the block ends, even after an exception.line-seqreturns a lazy sequence of lines. Consume it (ordoallit) insidewith-open— reading after the file is closed throws an error.
Writing with a writer
(require '[clojure.java.io :as io])
(with-open [w (io/writer "report.txt")]
(.write w "Report\n")
(doseq [i (range 1 4)]
(.write w (str "item " i "\n"))))
(print (slurp "report.txt"))
(binding [*out* (io/writer "report.txt")]
(println "printed straight into the file")
(flush))
(print (slurp "report.txt"))
Report
item 1
item 2
item 3
printed straight into the file
binding temporarily redirects *out*, so println writes to the file.
Files and directories
(require '[clojure.java.io :as io])
(io/make-parents "project/src/app.clj") ; create missing folders
(spit "project/src/app.clj" "(println :app)")
(spit "project/README.md" "# Project")
(let [root (io/file "project")]
(println (sort (for [f (file-seq root) :when (.isFile f)]
(.replace (str (.relativize (.toPath root) (.toPath f))) "\\" "/"))))
(println (.exists (io/file "project/README.md")))
(doseq [f (reverse (file-seq root))] (io/delete-file f))
(println (.exists root)))
(README.md src/app.clj)
true
false
io/filebuildsjava.io.Fileobjects;file-seqwalks a directory tree.- Deleting in
reverseorder removes files before their folders. io/resourcefinds files on the classpath (likeresources/config.edn) — the usual way to ship data files with an application.