企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## 输入/输出 Clojure提供了很少的方法来进行输入/输出的操作。因为我们在Clojure代码里面可以很轻松的使用java里面的I/O操作方法。但是?clojure.java.io 库使得使用java的I/O方法更加简单。 这些预定义的special symbols `*in*` , `*out*` 以及 `*err*` 默认被设定成 stdin, stdout 以及 stderr 。如果要flush `*out*` ,里面的输出,使用 `(flush)` 方法,效果和 `(.flush *out*)` 一样。当然这些symbol的binding是可以改变的。比如你可以把输出重定向到 " `my.log` "文件里面去。 看下面的例子: ``` (binding [*out* (java.io.FileWriter. "my.log")] ... (println "This goes to the file my.log.") ... (flush)) ``` `print` 可以打印任何对象的字符串表示到*out*,并且在两个对象之间加一个空格。 `println` 函数和 `print` 类似, 但是它会在最后加一个newline符号。默认的话它还会有一个flush的动作。这个默认动作可以通过把 special symbol `*flush-on-newline*` 设成 `false` 来取消掉。 `newline` 函数写一个newline符号 `*out*` 流里面去。 在调用 `print` 函数后面手动调用 `newline` 和直接调用 `println` 的效果是一样的。 `pr` 与 `prn` 是和 `print` 与 `println` 想对应的一对函数, 但是他们输出的形式可以被 Clojure reader去读取。它们对于把Clojure的对象进行序列化的时候比较有用。默认情况下它们不会打印数据的元数据。可以通过把 special symbol `*print-meta*` 设置成 `true` 来调整这个行为。 下面的例子演示了我们提到的四个打印方法。注意使用print和pr输出的字符串的不同之处。 ``` (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` 类似, 只是它们返回一个字符串,而不是把他们打印出来。 `printf` 函数和 `print` 类似。但是它接受一个format字符串。 `format` 函数和 `printf` , 类似,只是它是返回一个字符串而不是打印出来。 宏 `with-out-str` 把它的方法体里面的所有输出汇总到一个字符串里面并且返回。 `with-open` 可以自动关闭所关联的连接(.close)方法, 这对于那种像文件啊,数据库连接啊,比较有用,它有点像C#里面的using语句。 `line-seq` 接受一个 `java.io.BufferedReader` 参数,并且返回一个LazySeq, 这个LazySeq包含所有的一行一行由BufferedReader读出的文本。返回一个LazySeq的好处在于,它不用马上读出文件的所有的内容, 这会占用太大的内存。相反, 它只需要在需要使用的时候每次读一行出来即可。 下面的例子演示了 `with-open` 和 `line-seq` 的用法。 它读出一个文件里面所有的行, 并且打印出包含某个关键字的那些行。 ``` (use '1) (defn print-if-contains [line word] (when (.contains line word) (println line))) (let [file "story.txt" word "fur"] ; with-open will close the reader after ; evaluating all the expressions in its body. (with-open [rdr (reader file)] (doseq [line (line-seq rdr)] (print-if-contains line word)))) ``` `slurp` 函数把一个文件里面的所有的内容读进一个字符串里面并且返回。 `spit` 把一个字符串写进一个文件里面然后关闭这个文件。 这篇文章只是大概过了一下clojure的io里面提供了哪些函数来进行I/O操作。大家可以看下clojure源文件: `clojure/java/io.clj` 以了解其它一些函数。