【问题标题】:How to use clojure.edn/read to get a sequence of objects in a file?如何使用 clojure.edn/read 获取文件中的对象序列?
【发布时间】:2013-02-20 12:11:36
【问题描述】:

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

我怎样才能打印出所有对象?考虑到其中一些可能是 nil,似乎我需要检查 EOF 或类似的东西。我想要一系列与我从line-seq 获得的对象相似的对象。

【问题讨论】:

    标签: clojure edn


    【解决方案1】:

    使用 :eof 键

    http://clojure.github.com/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)))))
    

    应该这样做

    【讨论】:

    • 是的,它就在文档中。哎呀。必须为 EOF 定义我自己的哨兵感觉有点脏,但也许我还没有弄清楚为什么这是正确的解决方案。
    • 参见@bfontaine 的 cmets 其他答案。具有内容独立性是有价值的,但您可以通过使用任何不可序列化为 EDN 的 :eof 键值来实现。
    【解决方案2】:

    我又看了一遍。这是我想出的:

    (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-seqclojure.edn/read 具有相同的签名,并保留所有现有行为,鉴于人们可能以不同方式使用:eof 选项,我认为这一点很重要。包含 EOF 异常的单独函数似乎是一个更好的选择,尽管我不确定如何最好地捕获它,因为它显示为 java.lang.RuntimeException

    【讨论】:

    • 使用:eof 参数而不是测试异常文本。
    • 老问题/答案,但你为什么这么说?如果您使用:eof 实现,那么您就不是内容独立的。甚至:library/eof 也可能发生冲突。避免的唯一方法是强制用户自己传递 :eof 值作为swallow-eof 的一部分。
    • EDN 是 Clojure 值的子集,因此您所要做的就是提供一个不能作为 EDN 序列化的 Clojure 值,就像函数一样。
    • 好点。这似乎是正确的做法。我试图举一个例子,但在 cmets 中格式化很棘手​​。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多