原帖地址:http://java.ociweb.com/mark/clojure/article.html#IO
作者:R. Mark Volkmann
译者:RoySong
Input/Output
Clojure提供了针对I/O操作的最小限度函数集合。因为在Clojure代码可以轻松调用java代码,所以针对I/O操作
经常使用的是java.io包中的类。然而,在 Clojure Contrib 中的duck-streams库使得对java io类库的调用更简单。
预定义的特殊符号*in* , *out*和 *err*默认提供了标准输入、输出和错误的功能。在 *out*中flush流输出可以采用
(flush),这等同于 (.flush *out*)。这些特殊符号的绑定是可以修改的。举个例子,将默认输出重定向为往文件“
my.log”中:
(binding [*out* (java.io.FileWriter. "my.log")] ... (println "This goes to the file my.log.") ... (flush))
print函数可以输出以空格分隔的 任意数目 对象的字符串表现到 特殊符号*out*的流中。
println函数类似print,不同点在于它会在每次输出的后面加上换行符。默认情况下,它会刷新输出。这个可以通过
指定特殊符号*flush-on-newline*为false来改变。
newline函数会为*out*中的流添加上换行符,在print后面跟上 newline的执行结果等同于println。
pr和 prn函数和print以及println很相似,不过它们的输出在一个form当中,这个form能够被Clojure reader读取。它们
适合序列化Clojure的数据结构。默认情况下,它们不会打印元数据。这个可以通过绑定特殊符号*print-meta*为true来改变。
下面的例子展示了四种打印函数,注意在采用pr和print时打印字符串和字符的差异:
(let [obj1 "foo"
obj2 {:letter \a :number (Math/PI)}] ; a map
(println "Output from print:")
(print obj1 obj2)
(println "Output from println:")
(println obj1 obj2)
(println "Output from pr:")
(pr obj1 obj2)
(println "Output from prn:")
(prn obj1 obj2))
上面的代码输出如下:
Output from print:
foo {:letter a, :number 3.141592653589793}Output from println:
foo {:letter a, :number 3.141592653589793}
Output from pr:
"foo" {:letter \a, :number 3.141592653589793}Output from prn:
"foo" {:letter \a, :number 3.141592653589793}
上面提到的所有函数都在输出的参数之间有个空格,采用str函数可以避免这个空格。它连接了所有输出参数的字符串
表现,例子如下:
(println "foo" 19) ; -> foo 19 (println (str "foo" 19)) ; -> foo19
print-str , println-str , pr-str 和prn-str同 print , println , pr和 prn很相似,但是输出的目标从 *out*变成了一个字符串,这个字符串也做为它们的返回值。
with-out-str宏捕获它内部所有表达式的输出并把这些输出放置在一个字符串中,然后将这个字符串做为返回值。
with-open宏接受任意数量的对象绑定,在它内部的表达式执行完毕后会调用对象的 .close方法。这是为了处理需要
关闭的资源诸如文件或者数据库连接而设定的。
line-seq函数接受一个 java.io.BufferedReader做为参数,并返回一个延迟序列,序列中包含了参数中读取到的所有
文本行。返回“延迟”序列的意义在于,在序列被调用时不会读取到所有的文本行, 这样就不会消耗太多内存。每次请求
延迟序列时,只会读取对应的一行。
下面的例子展示了with-open 和line-seq的使用,它会读取某文件中的所有行,并输出包含某个特定字符的行。它采用了
两种方式,先是with-open,然后是 line-seq,它们都包含在 Clojure Contrib 的duck-streams库中。
(use '[clojure.contrib.duck-streams :only (read-lines)])
(defn print-if-contains [line word]
(when (.contains line word) (println line)))
(let [file "story.txt"
word "fur"]
; with-open will close the FileReader and BufferedReader
; after evaluating all the expressions in its body.
(with-open [fr (java.io.FileReader. file)
br (java.io.BufferedReader. fr)]
(doseq [line (line-seq br)] (print-if-contains line word)))
; read-lines closes the Reader it creates
; after all the lines it returns in a lazy sequence are consumed.
(doseq [line (read-lines file)] (print-if-contains line word)))
slurp函数读取文件的整个文本并放置在返回结果的字符串中, duck-streams库提供了spit函数来将字符串写入到
文件中并关闭文件。
这篇文章仅仅涉及到duck-streams库的表层而已,去阅读duck-streams.clj文件学习其中定义的函数是更好的选择。

本文详细介绍了Clojure中的输入输出方法,包括特殊符号的使用、打印函数、流处理函数等,并通过示例展示了如何进行文件读写操作。

被折叠的 条评论
为什么被折叠?



