我正在处理 60GB 或更大的文本文件。这些文件被分成可变长度的标题部分和数据部分。我有三个功能:
head?
区分标题行和数据行的谓词 process-header
处理一个标题行字符串 process-data
处理一个数据行字符串我从另一个 SO 线程推进了一种文件读取方法,它应该构建一个惰性的行序列。这个想法是用一个函数处理一些行,然后切换一次函数并继续处理下一个函数。
(defn lazy-file
[file-name]
(letfn [(helper [rdr]
(lazy-seq
(if-let [line (.readLine rdr)]
(cons line (helper rdr))
(do (.close rdr) nil))))]
(try
(helper (clojure.java.io/reader file-name))
(catch Exception e
(println "Exception while trying to open file" file-name)))))
我将它与类似的东西一起使用
(let [lfile (lazy-file "my-file.txt")]
(doseq [line lfile :while head?]
(process-header line))
(doseq [line (drop-while head? lfile)]
(process-data line)))
尽管这可行,但由于以下几个原因,它的效率相当低:
process-head
直到我得到数据,然后继续 process-data
,我必须过滤标题行并处理它们,然后重新解析整个文件并删除所有标题行以处理数据。这与 lazy-file
完全相反。打算做的。 那么使用我的数据库的更有效、更惯用的方法是什么?
一种想法可能是使用多方法来处理取决于
head?
的值的标题和数据。谓词,但我认为这会对速度产生一些严重的影响,特别是因为只有一次发生谓词结果从始终为真变为始终为假的情况。我还没有对此进行基准测试。使用另一种方式构建行序列并使用
iterate
解析它会更好吗? ?这仍然让我需要使用 :while 和 :drop-while,我猜。在我的研究中,多次提到使用 NIO 文件访问,这应该可以提高内存使用率。我还不知道如何在 clojure 中以惯用的方式使用它。
也许我对大体的想法还没有把握,文件应该如何处理?
与往常一样,非常感谢任何帮助、想法或指向 tuts 的指示。
最佳答案
您应该使用标准库函数。
line-seq、with-open 和 doseq 可以轻松完成这项工作。
符合以下条件的东西:
(with-open [rdr (clojure.java.io/reader file-path)]
(doseq [line (line-seq rdr)]
(if (head? line)
(process-header line)
(process-data line))))
关于Clojure - 处理内存不足的大文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34329821/