如何在 Clojure 中处理大型二进制数据文件?我们假设数据/文件大约为 50MB - 小到足以在内存中处理(但不是简单的实现)。
以下代码正确地从小文件中删除 ^M 但它会抛出OutOfMemoryError
对于较大的文件(如 6MB):
(defn read-bin-file [file]
(to-byte-array (as-file file)))
(defn remove-cr-from-file [file]
(let [dirty-bytes (read-bin-file file)
clean-bytes (filter #(not (= 13 %)) dirty-bytes)
changed? (< (count clean-bytes) (alength dirty-bytes))] ; OutOfMemoryError
(if changed?
(write-bin-file file clean-bytes)))) ; writing works fine
看起来Java字节数组不能被视为seq因为它的效率极低。
另一方面,解决方案aset
, aget
and areduce
臃肿、丑陋且势在必行,因为您无法真正使用 Clojure 序列库。
我缺少什么?如何在 Clojure 中处理大型二进制数据文件?
我个人可能会在这里使用 aget / aset / areduce - 它们可能是必要的,但在处理数组时它们是有用的工具,而且我不认为它们特别难看。如果你想将它们包装在一个好的函数中,那么你当然可以:-)
如果您决定使用序列,那么您的问题将在于 seq 的构造和遍历,因为这将需要为数组中的每个字节创建和存储一个新的 seq 对象。每个数组字节可能约为 24 个字节……
因此,诀窍是让它惰性地工作,在这种情况下,在到达数组末尾之前,较早的对象将被垃圾收集。然而,为了使其工作,您必须避免在遍历序列时(例如使用 count)保留对 seq 头部的任何引用。
以下可能有效(未经测试),但取决于以惰性友好方式实现的 write-bin-file:
(defn remove-cr-from-file [file]
(let [dirty-bytes (read-bin-file file)
clean-bytes (filter #(not (= 13 %)) dirty-bytes)
changed-bytes (count (filter #(not (= 13 %)) dirty-bytes))
changed? (< changed-bytes (alength dirty-bytes))]
(if changed?
(write-bin-file file clean-bytes))))
请注意,这本质上与您的代码相同,但构造了一个单独的惰性序列来计算更改的字节数。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)