在clojure中将大文件写入磁盘

det*_*ran 4 csv clojure

我有一个返回大量行的 sql 查询。我想将查询结果保存到磁盘上的 csv 文件中。但是,因为有太多行,所以在 sql 查询可以聚合所有行之前,我的内存不足。

它看起来像这样,并且在查询部分失败:

(-> query format-transformer csv-writer)
Run Code Online (Sandbox Code Playgroud)

det*_*ran 5

我在#clojure irc 频道的帮助下弄明白了。你需要两个库:

(ns myproj.example
  (:require [[clojure.java.jdbc :as sql]
             [clojure.data.csv :as csv]]))
Run Code Online (Sandbox Code Playgroud)

诀窍是在返回时处理每一行,然后将其丢弃。java jdbc 库具有查询功能,该功能使用:row-fn:result-set-fn选项提供此功能。

(defn sql->csv  [title]
  (with-open [w (clojure.java.io/writer (str title ".csv") :append true)]
   (sql/query ds (second query)
             :row-fn (fn [row]
                       (csv/write-csv w  [(mapv str (vals row))]))
             :result-set-fn dorun)))
Run Code Online (Sandbox Code Playgroud)

有趣的部分是:row-fn:result-set-fn

:row-fn分派每一个行从查询返回的时间。每一行都是表格中的一张地图{:column1 "data" :column2 "data2"}。我们改变地图到的东西,写的csv可以使用(嵌套向量)与此:[(mapv str (:vals row)])。然后 write-csv 将其附加到您提供的文件中。

:result-set-fn对于不炸毁堆至关重要。通过将其设置为dorun您告诉它在处理时丢弃头部。

这个特定的实现不提供列标题,这是留给读者的练习(我的太尴尬了,无法在公共论坛上发布)。