如何在Clojure中逐行惰性地读取文件目录
我试图一行一行地惰性地读取json文件目录,这样我就可以惰性地对数据执行操作如何在Clojure中逐行惰性地读取文件目录,clojure,io,seq,Clojure,Io,Seq,我试图一行一行地惰性地读取json文件目录,这样我就可以惰性地对数据执行操作 我不断得到java.io.IOException:streamclosed——我如何在不过早关闭阅读器的情况下使用它 问题在于,当程序退出它所包含的作用域时,open调用。close,但所有行不一定都被该点读取 我的解决方案可能是一个本不该出现在光天化日之下的恶习,但我的想法是:创建一个“lazy seq”只调用.close,并将其连接到行seq列表的末尾: (->> "/Users/micahsmith/
我不断得到
java.io.IOException:streamclosed
——我如何在不过早关闭阅读器的情况下使用它 问题在于,当程序退出它所包含的作用域时,open调用。close
,但所有行不一定都被该点读取
我的解决方案可能是一个本不该出现在光天化日之下的恶习,但我的想法是:创建一个“lazy seq
”只调用.close
,并将其连接到行seq
列表的末尾:
(->> "/Users/micahsmith/printio/gooten-import-ai/jupyter/data"
File.
file-seq
(filter #(-> ^File % .getAbsolutePath (str-contains? ".json")))
(mapcat (fn [^File file]
(with-open [ rdr (io/reader file)]
(line-seq rdr)))))
从我对桌面上的文件的快速测试来看,它似乎可以工作。如果将println
添加到终止的lazy seq
中,它将按预期打印,因此文件将被关闭
不过,我不太愿意提出这个解决方案,因为它依赖于在懒散列表中执行副作用,而我习惯于“感觉错误”,原因很明显。此方法的主要缺点是,除非对整个序列进行求值,否则不会关闭文件,并且文件将一直保持打开状态,直到到达结束。考虑到这些限制,我不认为这两个问题都可以避免
我意识到我用的是“懒猫”有点错误。我有一个额外的、不必要的
lazy seq
包装器。现在修好了。你也可以用类似的东西
(defn lazy-lines [^File file]
(let [rdr (io/reader file)]
(lazy-cat (line-seq rdr)
(do (.close rdr)
nil)))) ; Explicit nil to indicate termination
(defn get-lines [^String path]
(->> path
(File.)
(file-seq)
(filter #(-> ^File % (.getAbsolutePath) (clojure.string/includes? ".json")))
(mapcat lazy-lines)))
使用打开功能的是为了阻止您这样做,而不是
懒猫
,因为您应该小心处理文件句柄和其他操作系统资源,而不是懒惰地处理。您打算使用open在的动态范围内对文件内容进行所有处理。因此,您不应该返回惰性序列,而应该接受函数作为参数,并在仍然在open的范围内的情况下对惰性序列调用该函数。该函数当然不应该返回另一个惰性序列,而是在返回之前处理其整个输入
所以这种东西的典型用途是:
(apply concat (line-seq rdr)
(lazy-seq (do (.close rdr)
nil))))))
当您有一个带有打开序列的列表时,情况会稍微复杂一些-您不能只调用进程一次。您可以做的一件事是在每个文件上返回调用process
的结果列表:
(defn process-file [filename process]
(with-open [f (io/reader filename)]
(process (line-seq f))))
然后,如果您需要对其执行一些全局操作,您可以减少处理文件的结果
这里的答案应该很有用:只是让人问一下:那些“json”文件可以逐行读取吗?e、 它们更像一行一个json对象?
(defn process-files [filenames process]
(for [filename filenames]
(with-open [f (io/reader filename)]
(process (line-seq f)))))