【发布时间】:2012-01-05 11:13:09
【问题描述】:
我需要编写一个函数,根据字段的值将记录拆分为单独的文件。例如。给定输入:
[
["Paul" "Smith" 35]
["Jason" "Nielsen" 39]
["Charles" "Brown" 22]
]
我们最终得到一个文件"Paul",包含"Paul Smith 35",文件"Jason",包含"Jason Nielsen 39",等等
我事先不知道名字,所以我需要保留作者的参考,以便我最终可以关闭它们。
我能想到的最好办法是使用 ref 来保留作者,如下所示:
(defn write-split [records]
(let [out-dir (io/file "/tmp/test/")
open-files (ref {})]
(try
(.mkdirs out-dir)
(dorun
(for [[fst lst age :as rec] records]
(binding [*out* (or
(@open-files fst)
(dosync
(alter open-files assoc fst (io/writer (str out-dir "/" fst)))
(@open-files fst)))]
(println (apply str (interpose " " rec))))))
(finally (dorun (map #(.close %) (vals @open-files)))))))
这可行,但感觉很糟糕,更重要的是,堆用完了,即使我只有五个输出文件,它们在一开始是打开的。好像有什么东西被保留下来了……
谁能想到一个功能更强大、更类似于 Clojure 的解决方案?
编辑:输入很大。潜在的千兆字节数据,因此内存效率的重要性以及每次写入后都不愿意关闭文件。
【问题讨论】:
-
记录数据太大了不能在内存中分组?
(group-by first records)然后为返回的映射中的每个新键打开和关闭一个文件。 -
是的,它很大——数千兆字节的数据通过惰性序列传入。理想情况下是无限的。
-
是否需要保持文件打开,或者需要打开的文件总数是有限的?大多数操作系统只允许打开一定数量的文件。
-
有限,少量文件 - 最多 20 个。严格来说,它们不需要打开,但每次写入后关闭文件(与 with-open 宏一样)不是一个选项.