Clojure:逐行读取 edn 文件

Clojure : Read an edn file line by line

我已经在文件中写入了这样的数据(有点)

{:a 25 :b 28}
{:a 2 :b 50}
...

我想要这些地图的惰性序列。

大约有 4000 万行。我也可以写 10000 的块,但我不认为它会改变函数的编写方式(mapcat 而不是 map

为了阅读,我写了

(with-open [affectations (io/reader "dev-resources/affectations.edn")]
  (map read-string affectations))

问题是Clojure告诉

Don't know how to create ISeq from : java.io.BufferedReader

老实说,我对 java.io 命名空间一无所知。 我想在文件中有一个惰性数据序列,但我不知道如何将流转换为字符串,然后再转换为集合。

有什么想法吗?

这是read-line吗?

谢谢

您正在将 java.io.BufferedReader 传递给 map,而 map 需要一个序列。

您需要使用 line-seq 从您的文件中生成一个(惰性)行序列:

(with-open [affectations (io/reader "dev-resources/affectations.edn")]
  (map read-string (lazy-seq affectations)))

请记住,您需要在其范围内强制对从 with-open 打开的资源读取的数据产生所有副作用,否则会出错。

一个选项是强制从您的文件中提取整个文本行序列,然后 return 使用 doall。但是,此解决方案可能会将您的所有数据读入内存,这似乎不切实际。

我想您需要为文件中的每一行执行一些逻辑,并且您不需要将所有这些已解析的集合保存在内存中。在这种情况下,您可以将表示该逻辑的函数传递到处理读取文件的函数中:

(defn process-file [filename process-fn]
  (with-open [reader (io/reader filename)]
    (doseq [line (line-seq reader)]
      (-> line
        (read-string)
        (process-fn)))))

此函数将逐行读取您的文件,使用 read-string 单独转换每个文件并调用您的 process-fn 函数。 process-file 将 return nil.