我一直在使用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 ,它向您展示了如何使用代理写入使用未来的文件。
首先,我使用 FileOutputStream 而不是 FileWriter,它仍然可以工作,但在本教程的示例中,您只需使用 .write 将字符串附加到文件末尾,然后关闭,我每次都需要重写文件“追加”(我认为?)因为 .xlsx 工作簿中的字节数不仅仅是字符。
我真的不知道如何设置它,因为使用教程的日志记录示例,写出返回 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 做到这一点,所以它更整洁。一个缺点是如果出现问题,根本不会将任何数据写入文件,但好处是减少了写入所需的时间,因为只有一次写入调用。此外,我每次都会将大量数据加载到内存中,这需要时间。无论哪种方式,内存使用情况都是相同的。
如果有人仍然想回答这个问题,我仍然会感兴趣,但是我第一次更新中的方法不起作用(每个未来都读取一个空文件并使用它来追加)。我将发布该代码,以防它对任何人有所帮助——上述教程的文档版本:
(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)]]))))
谢谢