Reputation: 3999
In clojure, how do I read a file into a sequence where each line is one element in the sequence. So I'd like to see the definition of the function get-lines
so I could do the following:
(def lines (get-lines "test.txt"))
and lines is a non-lazy sequence.
Upvotes: 6
Views: 7570
Reputation: 3217
Alternate implementation:
(require ['clojure.string :as 'str])
(defn get-lines [file]
(str/split-lines (slurp file)))
This function returns a vector of the results instead of a seq.
If you are not using 1.3, require clojure.contrib.string instead.
Upvotes: 12
Reputation: 19642
You could use line-seq
. A quick example:
(ns your.project
(:require [clojure.java.io :as io]))
(defn count-lines [filename]
(with-open [rdr (io/reader filename)]
(count (line-seq rdr))))
Note that line-seq
is lazy. You must be careful not to consume the sequence after the reader is closed. The following will not work:
(def lines (with-open [rdr (io/reader "some-file")]
(line-seq rdr)))
(println (first lines))
The first example works because count
isn't lazy.
If you want to do something (with side effects) with the lines you'll probably find doseq
most useful:
;; copy every "short" line in file
(with-open [rdr (io/reader from)
wrt (io/writer to)]
(binding [*out* wrt]
(doseq [line (line-seq rdr) :when (< (count line) 10)]
(println line))))
Upvotes: 2
Reputation: 6008
To convert lazy sequence to non-lazy you can use doall
like so:
(use 'clojure.java.io)
(defn get-lines [fname]
(with-open [r (reader fname)]
(doall (line-seq r))))
Upvotes: 10