如何使用clojure.edn/read从文件中获取对象序列?

13
Clojure 1.5引入了clojure.edn,其中包括一个需要PushbackReader的读取函数。
如果我想读取前五个对象,可以执行以下操作:
(with-open [infile (java.io.PushbackReader. (clojure.java.io/reader "foo.txt"))]
  (binding [*in* infile]
    (let [edn-seq (repeatedly clojure.edn/read)]
      (dorun (take 5 (map println edn-seq))))))

我该如何打印出所有的对象?考虑到其中一些可能为空,似乎需要检查EOF或类似的东西。我想要一个类似于line-seq的对象序列。

2个回答

16
使用 :eof 关键字

https://clojure.github.io/clojure/clojure.edn-api.html

opts是一个映射表,可以包含以下键::eof-在文件结束时返回的值。当未提供时,EOF会抛出异常。

编辑:不好意思,那不够详细!看这里:

(with-open [in (java.io.PushbackReader. (clojure.java.io/reader "foo.txt"))]
  (let [edn-seq (repeatedly (partial edn/read {:eof :theend} in))]
    (dorun (map println (take-while (partial not= :theend) edn-seq)))))

那应该就可以了


1
是的,它就在文档中。哎呀。不得不为EOF定义自己的标记感觉有点不好,但也许我还没有理解为什么这是正确的解决方案。 - ToBeReplaced
请参考@bfontaine在另一个回答中的注释。拥有独立于内容的价值是有意义的,但您可以通过使用任何不可序列化为EDN的值来实现这一点,使其成为可能。 - ToBeReplaced

3

我再次仔细查看了这个问题。以下是我的结论:

(defn edn-seq
  "Returns the objects from stream as a lazy sequence."
  ([]
     (edn-seq *in*))
  ([stream]
     (edn-seq {} stream))
  ([opts stream]
     (lazy-seq (cons (clojure.edn/read opts stream) (edn-seq opts stream)))))

(defn swallow-eof
  "Ignore an EOF exception raised when consuming seq."
  [seq]
  (-> (try
        (cons (first seq) (swallow-eof (rest seq)))
        (catch java.lang.RuntimeException e
          (when-not (= (.getMessage e) "EOF while reading")
            (throw e))))
      lazy-seq))

(with-open [stream (java.io.PushbackReader. (clojure.java.io/reader "foo.txt"))]
  (dorun (map println (swallow-eof (edn-seq stream)))))

edn-seq 的签名与 clojure.edn/read 相同,并保留了所有现有的行为,这一点非常重要,因为人们可能以不同的方式使用:eof 选项。一个单独的函数来包含 EOF 异常似乎是更好的选择,尽管我不确定如何最好地捕获它,因为它只显示为一个 java.lang.RuntimeException


使用 :eof 参数而不是测试异常文本。 - bfontaine
老问题/答案,但你为什么这么说?如果你使用:eof实现,那么你就不是内容无关的。即使是:library/eof也可能会发生冲突。唯一避免的方法是强制用户将一个:eof值作为swallow-eof的一部分传递进来。 - ToBeReplaced
EDN是Clojure值的子集,所以您只需要提供一个不可序列化的Clojure值作为EDN,例如函数。 - bfontaine
好的观点。这似乎是正确的做法。我试图给出一个例子,但在评论中进行格式设置很棘手。谢谢! - ToBeReplaced

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接