在Clojure 1.3中,如何读取和写入文件

我想知道在clojure 1.3中读取和写入文件的“推荐”方法。

  1. 如何阅读整个文件
  2. 如何逐行读取文件
  3. 如何写一个新的文件
  4. 如何将行添加到现有的文件

假设我们只在这里做文本文件,而不是一些疯狂的二进制文件。

数字1:如何将整个文件读入内存。

(slurp "/tmp/test.txt") 

当它是一个非常大的文件时不推荐。

第二:如何逐行读取文件。

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

with-openmacros需要注意读者在身体的尽头closures。 阅读器function强制一个string(它也可以做一个URL等)到一个BufferedReaderline-seq提供了一个懒惰的seq。 要求懒惰的seq结果的下一个元素成为从阅读器读取的一行。

3号:如何写入一个新的文件。

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

再一次, with-open需要注意BufferedWriter在主体的末尾是closures的。 Writer将一个string(.write wrtr "something").转换为BufferedWriter ,通过java interop使用use:( (.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 ,反之亦然:

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

PS:为了更清楚地知道您正在读取和写入文件而不是别的东西,您可以先创build一个File对象,然后将其强制到一个BufferedReader或Writer中:

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

文件function也在clojure.java.io中。

PS2:有时能够看到当前目录(如“。”)是什么方便。 你可以通过两种方式获得绝对path:

 (System/getProperty "user.dir") 

要么

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

如果文件适合内存,你可以阅读和写入唾液和吐:

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

(现在包含一个文件的内容作为一个string)

 (spit "newfile.txt" s) 

这将创buildnewfile.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

关于问题2,人们有时候希望返回的stream作为第一类对象。 为了得到这个作为一个懒惰的序列,并仍然在EOF自动closures文件,我用这个函数:

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

这是如何读取整个文件。

如果该文件在资源目录中,则可以这样做:

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

记得要求/使用clojure.java.io

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