如何在Clojure中处理大型二进制数据?

时间:2010-08-21 20:25:15

标签: clojure binary-data

如何在Clojure中处理大型二进制数据文件?假设数据/文件大约为50MB - 小到足以在内存中处理(但没有简单的实现)。

以下代码正确地从小文件中删除了^ M,但是对于较大的文件(例如6MB),它会抛出OutOfMemoryError

(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 ,因为效率极低。

另一方面,asetagetareduce的解决方案变得臃肿,丑陋且势在必行,因为您无法真正使用Clojure序列库。

我错过了什么? 如何在Clojure中处理大型二进制数据文件?

1 个答案:

答案 0 :(得分:6)

我个人可能会在这里使用aget / aset / areduce - 它们可能是必要的但它们在处理数组时是很有用的工具,我觉得它们并不特别难看。如果你想将它们包装在一个很好的功能中,那么你当然可以: - )

如果您决定使用序列,那么您的问题将在seq的构造和遍历中,因为这将需要为数组中的每个字节创建和存储新的seq对象。对于每个数组字节,这可能是~24个字节......

所以诀窍就是让它懒散地运行,在这种情况下,在你到达数组末尾之前,早期的对象将被垃圾收集。但是,要使其工作,您必须避免在遍历序列时保持对seq头部的任何引用(例如,使用count)。

以下可能有效(未经测试),但将依赖于以惰性友好方式实现的write-bin文件:

(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))))

请注意,这与您的代码基本相同,但构造一个单独的延迟序列来计算更改的字节数。