我想知道在clojure 1.3中读取和写入文件的“推荐”方式。
答案 0 :(得分:264)
假设我们这里只做文本文件而不是一些疯狂的二进制文件。
数字1:如何将整个文件读入内存。
(slurp "/tmp/test.txt")
当它是一个非常大的文件时不推荐。
数字2:如何逐行阅读文件。
(use 'clojure.java.io)
(with-open [rdr (reader "/tmp/test.txt")]
(doseq [line (line-seq rdr)]
(println line)))
with-open
宏注意读者在身体末端关闭。 reader函数将字符串(它也可以执行URL等)强制转换为BufferedReader
。 line-seq
提供了一个懒惰的seq。要求延迟seq的下一个元素成为从读者读取的行。
请注意,从Clojure 1.7开始,您还可以使用transducers来阅读文本文件。
编号3:如何写入新文件。
(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
(.write wrtr "Line to be written"))
同样,with-open
会关注BufferedWriter
在身体末端关闭。 Writer将字符串强制转换为BufferedWriter
,您可以通过java interop使用它:(.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
再次与slurp
相反:
(spit "/tmp/test.txt" "Line to be written" :append true)
PS:要更明确地说明您正在阅读和写入文件而不是其他内容,您可以先创建一个File对象,然后将其强制转换为{{1}或者作家:
BufferedReader
文件功能也在clojure.java.io中。
PS2:有时能够看到当前目录(所谓的“。”)是很方便的。您可以通过两种方式获得绝对路径:
(reader (file "/tmp/test.txt"))
;; or
(writer (file "tmp/test.txt"))
或
(System/getProperty "user.dir")
答案 1 :(得分:32)
如果文件适合内存,你可以用slurp和spit读取和写入:
(def s (slurp "filename.txt"))
(现在包含作为字符串的文件内容)
(spit "newfile.txt" s)
如果它不退出并写入文件内容,则会创建newfile.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's BufferedReader Java's Writer
答案 2 :(得分:6)
关于问题2,人们有时希望将流作为第一类对象返回。为了让它成为一个懒惰的序列,并且仍然在EOF上自动关闭文件,我使用了这个函数:
(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)))
答案 3 :(得分:1)
这是阅读整个文件的方法。
如果文件位于资源目录中,则可以执行以下操作:
(let [file-content-str (slurp (clojure.java.io/resource "public/myfile.txt")])
记得要求/使用clojure.java.io
答案 4 :(得分:0)
(require '[clojure.java.io :as io])
(io/copy (io/file "/etc/passwd") \*out*\)
答案 5 :(得分:0)
要逐行读取文件,您不再需要互操作:
import urllib3
url = 'http://q32wad/documents/bills.pdf'
http = urllib3.PoolManager()
headers = urllib3.util.make_headers(basic_auth='username123:password123')
r = http.request('GET', url, headers=headers)
print("STATUS = " + str(r.status))
print("HEADERS = " + str(r.headers))
results:
STATUS = 200
HEADERS = HTTPHeaderDict({'Date': 'Sun, 05 Aug 2018 15:07:32 GMT', 'Server': 'Apache', 'Content-Length': '636', 'Content-Type': 'text/html;charset=ISO-8859-1'})
这假定您的数据文件保存在资源目录中,并且第一行是可以丢弃的标头信息。