我一直在使用docjure来写入excel文件。大多数情况下,我想将行追加到现有文件中,通常一次添加一行。当我在没有代理/未来的情况下执行此操作时,我加载文件,使用add-rows添加数据,然后重写文件,如下所示:
(defn append [filename data]
"data is in the same format as create-workbook, i.e. [[\"n\" \"m\"] [1 2] [3 4]]"
(let [workbook (load-workbook filename))
sheet (select-sheet workbook "Sheet1")]
(add-rows! sheet data)
(save-workbook! filename workbook)))
我做了很多追加的调用,所以我发现了这个:http://blakesmith.me/2012/05/25/understanding-clojure-concurrency-part-2.html,它告诉你如何使用代理来使用future来写入文件。
首先,我正在使用FileOutputStream而不是FileWriter,它仍然可以工作,除了在教程的示例中,您只需使用.write将字符串附加到文件末尾然后关闭,我需要重写文件每次我“追加”(我认为?),因为.xlsx工作簿中的字节数多于字符数。
我真的不知道如何设置它,因为在教程的日志记录示例中,write-out返回BufferedWriter的更新实例,我不知道它的等价物是什么。
我的另一个选择是同时将数据添加到矢量(加载文件一次并继续返回新的矢量[[\“n \”\“m \”] [1 2] [3 4]]数据已添加)但我正在计划进行~10000-100000的这些调用,这似乎要记住很多......尽管要公平地阅读和编写所有数据,但很多时候这些数据可能也不是那么好。
如果您对我如何做到这一点有任何建议,我会很感激。如果有更好的方法可以追加它,我也愿意自己调用Apache POI。感谢。
--- UDPATE ---
我刚刚用文件作为代理而不是输出流重写了记录器示例,它似乎工作正常。如果它最终使用docjure / Apache POI,我会告诉你。
(def logfile (agent (File. "blah.txt")))
(defn write-out [file msg]
(with-open [out (BufferedWriter. (FileWriter. file true))]
(.write out msg))
file)
--- UDPATE 2 ---
我得到了一个用docjure编写的类似版本,但不幸的是因为打开文件发生在写出中并且在每个未来发生(如果我使用File作为代理,我没有看到这种方法,而我除了那个之外没有其他方法可以做到这一点)大多数人都读取空文件并将行写入,因为它们都是并行完成的,最终结果是大多数都相互覆盖。
最终我决定将每个行向量添加到整个数据向量中并写入一次。我可以用pmap做到这一点,所以它更整洁。一个缺点是,如果出现问题,根本没有任何数据写入文件,但好处是,由于只有一次写入调用,因此写入所需的时间减少了。此外,我每次都会将大量数据加载到内存中,这需要时间。内存使用情况无论如何都是一样的。
如果有人还想回答这个问题,我仍然会感兴趣,但是我的第一次更新中的方法不起作用(每个将来读取一个空文件并使用它追加)。我将发布该代码,但它可以帮助任何人 - 上述教程的docjure版本:
(def file (agent (File. "blah.xlsx")))
(defn write-out [file workbook]
(with-open [out (FileOutputStream. file)]
(.write workbook out))
file)
(defn write-workbook [file data]
(let [filename (.getPath @file)
workbook (try (load-workbook filename)
(catch Exception e (create-workbook "Sheet1" [])))
sheet (select-sheet "Sheet1" workbook)]
(add-rows! sheet data)
(send file write-out workbook)))
(defn test [file]
(write-workbook file [["n" "m"]])
(dotimes [i 5]
(future (write-workbook file [[i (inc i)]]))))
由于