Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

read a file into a list, each element represents one line of the file

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.

like image 928
ftravers Avatar asked Jan 28 '12 17:01

ftravers


3 Answers

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.

like image 141
Retief Avatar answered Nov 19 '22 14:11

Retief


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))))
like image 32
MisterMetaphor Avatar answered Nov 19 '22 15:11

MisterMetaphor


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))))
like image 24
Jonas Avatar answered Nov 19 '22 14:11

Jonas