2

我有以下代码:

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

我想在读取文件后重新创建记录,但我不明白我是如何做到的。是的,我知道我可以解析文本并通过解析行的元素填充我的结构,但这会很困难,因为我有很多像“成员”和“角色”这样的结构。任何人都可以建议我一种方法,我可以做到吗?

4

2 回答 2

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/readclojure.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")
于 2013-09-22T18:33:12.673 回答
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)))))))

read.

这是一个小的变体,它将从字符串中读取所有对象:

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

于 2013-09-22T18:38:15.373 回答