我有以下代码:
(use 'clojure.java.io)
(defrecord Member [id name salary role])
(defrecord Role [id name])
(def member-records (ref ()))
(defn add-member [member]
(dosync (alter member-records conj member)))
;;Test-data -->
(def dev-r(->Role 1 "Developer"))
(def test-member1(->Member 1 "Kirill" 70000.00 dev-r))
;;Test-data <--
(defn save-data-2-file []
(with-open [wrtr (writer "C:/Platform/Work/test.cdf")]
(print-dup @member-records wrtr)))
(defn process-line [line]
(println line))
;;Test line content
;;#BTC.pcost.Member{:id 1, :name "Kirill", :salary 70000.0, :role #BTC.pcost.Role{:id 1, :name "Developer"}})
(defn load-data-from-file []
(with-open [rdr (reader "C:/Platform/Work/test.cdf")]
(doseq [line (line-seq rdr)]
(process-line line))))
我想在阅读文件后重新创建记录,但我无法理解我是如何做到的。是的,我知道我可以通过解析行的元素来解析文本并填充我的结构,但是它会很困难,因为我有很多像“成员”和“角色”这样的结构。任何人都可以建议我,我能做什么?
答案 0 :(得分:3)
您可以使用read-string
和slurp
将记录从文件中提取出来。 read-string
仅限于读取字符串的第一种形式,但是,从您的示例中,您只存储单个表单,作为记录列表。
(defn load-data-from-file [file]
(read-string (slurp file)))
如果您需要的不仅仅是第一个表单,或者无法将整个流读入内存,您可以直接使用read
来制作一个懒惰的读者。
(defn lazy-read
([rdr] (let [eof (Object.)] (lazy-read rdr (read rdr false eof) eof)))
([rdr data eof]
(if (not= eof data)
(cons data (lazy-seq (lazy-read rdr (read rdr false eof) eof))))))
(defn load-all-data [file]
(with-open [rdr (java.io.PushbackReader. (reader file))]
(doall (lazy-read rdr))))
(load-all-data "C:/Platform/Work/test.cdf")
此外,在使用read-string
或read
加载代码时,最好提及安全性。您只应将它们与受信任的源一起使用,因为使用#=
或Java构造函数,源可以在您的应用程序中执行任意代码。有关更长的说明,请查看read
的文档。
将*read-eval*
设置为false
会阻止此问题,但也会阻止重建样本中的记录。要一起避免此问题,您可以使用clojure.edn/read
和clojure.edn/read-string
功能以及读者白名单。
(defn edn-read [eof rdr]
(clojure.edn/read {:eof eof :readers {'BTC.pcost.Role map->Role
'BTC.pcost.Member map->Member}}
rdr))
(defn lazy-edn-read
([rdr] (let [eof (Object.)] (lazy-edn-read rdr (edn-read eof rdr) eof)))
([rdr data eof]
(if (not= eof data)
(cons data (lazy-seq (lazy-edn-read rdr (edn-read eof rdr) eof))))))
(defn load-all-data [file]
(with-open [rdr (java.io.PushbackReader. (reader file))]
(doall (take-while (complement nil?) (lazy-edn-read rdr)))))
(load-all-data "C:/Platform/Work/test.cdf")
答案 1 :(得分:2)
您可以使用read
。
此函数将从文件中读取一个对象:
(defn load-data-from-file [filename]
(with-open [rdr (java.io.PushbackReader. (reader filename))]
(read rdr)))
或者这将读取文件中的所有对象:
(defn load-all-data-from-file [filename]
(let [eof (Object.)]
(with-open [rdr (java.io.PushbackReader. (reader filename))]
(doall
(take-while #(not= % eof)
(repeatedly #(read rdr nil eof)))))))
Here's read
的API文档。
这是一个小变体,它将读取字符串中的所有对象:
(defn load-all-data-from-string [string]
(let [eof (Object.)]
(with-open [rdr (-> string java.io.StringReader. java.io.PushbackReader.)]
(doall
(take-while #(not= % eof)
(repeatedly #(read rdr nil eof)))))))
据我所知,这是不可能使用read-string
。相反,我们将read
与java.io.StringReader
一起使用。