In Clojure 1.3, How to read and write a file

jolly-san picture jolly-san · Oct 13, 2011 · Viewed 70.7k times · Source

I'd like to know the "recommended" way of reading and writing a file in clojure 1.3 .

  1. How to read the whole file
  2. How to read a file line by line
  3. How to write a new file
  4. How to add a line to an existing file

Answer

Michiel Borkent picture Michiel Borkent · Oct 13, 2011

Assuming we're only doing text files here and not some crazy binary stuff.

Number 1: how to read an entire file into memory.

(slurp "/tmp/test.txt")

Not recommended when it is a really big file.

Number 2: how to read a file line by line.

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

The with-open macro takes care that the reader is closed at the end of the body. The reader function coerces a string (it can also do a URL, etc) into a BufferedReader. line-seq delivers a lazy seq. Demanding the next element of the lazy seq results into a line being read from the reader.

Note that from Clojure 1.7 onwards, you can also use transducers for reading text files.

Number 3: how to write to a new file.

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

Again, with-open takes care that the BufferedWriter is closed at the end of the body. Writer coerces a string into a BufferedWriter, that you use use via java interop: (.write wrtr "something").

You could also use spit, the opposite of slurp:

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

Number 4: append a line to an existing file.

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

Same as above, but now with append option.

Or again with spit, the opposite of slurp:

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

PS: To be more explicit about the fact that you are reading and writing to a File and not something else, you could first create a File object and then coerce it into a BufferedReader or Writer:

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

The file function is also in clojure.java.io.

PS2: Sometimes it's handy to be able to see what the current directory (so ".") is. You can get the absolute path in two ways:

(System/getProperty "user.dir") 

or

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