2015-10-20 60 views
3

我有一個sql查詢返回大量的行。我想將查詢的結果保存到磁盤上的csv文件中。但是,因爲有太多的行在內存用完之前,所有行都可以通過sql查詢進行聚合。在clojure中寫入大文件到磁盤

它看起來像這樣,和查詢部分時失敗:

(-> query format-transformer csv-writer) 

回答

4

我想通了從#clojure IRC頻道一些幫助。你需要兩個庫:

(ns myproj.example 
    (:require [[clojure.java.jdbc :as sql] 
      [clojure.data.csv :as csv]])) 

訣竅是處理每一行,因爲它返回,然後丟棄它。 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))) 

有趣的部分是:row-fn:result-set-fn。每當從查詢返回一行時,:row-fn被調度。每一行都是{:column1 "data" :column2 "data2"}形式的地圖。我們將地圖更改爲write-csv可以使用的內容(嵌套向量):[(mapv str (:vals row)])。然後write-csv將它附加到您提供的文件中。

:result-set-fn對於不吹你的堆是至關重要的。通過將其設置爲dorun,您可以告訴它在處理完成後丟棄頭部。

這個特定的實現不提供列標題,這是留給讀者的一個練習(我的太尷尬了,在公共論壇上發佈)。

+0

我會假設你的':row-fn'現在打開並關閉每一行的文件。更糟糕的是,它必須掃描到您正在編寫的每行文件的末尾。我沒有對它進行測試,但我認爲如果您將'with-open'調用放到'sql/query'之外就可以提高效率。根據最新的[docs](https://clojure.github.io/java.jdbc/),我也認爲你實際上想設置':result-set-fn'而不是':row-set-fn' #clojure.java.jdbc /查詢)。我猜''result-set-fn'的默認'doall'可能會發生相同的變化,或者您使用的是舊版本。 – schaueho

+0

@schaueho:好的,謝謝。我已經測試過這些變化,並且它在'with-open'內更快。我試着將'write-csv'函數放在':result-set-fn'中,但最終返回的行數和nils一樣多。 – dan