我正在处理一个脚本,该脚本需要从磁盘读取成千上万个文件。我正在尝试了解执行此操作的最佳方法。我在使用map
和两个软件包clj-glob
和clojure-mail
来执行此操作时遇到了问题:
(def sent-mail-paths
(->> (str maildir-path "/*/_sent_mail/*")
(glob) ;; returns files using clojure.java.io/as-file
(map str) ;; i just want the paths
))
(def msgs
(->> sent-mail-paths ;; 30K + paths
(map mail/file->message)))
其中第一个块中的glob
函数来自clj-glob
,并使用as-file
返回一组文件对象(请参见here)。我只想要路径字符串,所以我做(map str)
。第二个块中的mail/file->message
函数使用with-open
和java FileInputStream
类来读取文件(请参见here)。
我遇到的麻烦是,当我尝试执行类似以下操作的结果时,这段代码会导致错误:
(count msgs)
错误是:
(系统中打开的文件太多)
我能够在这里完成工作的唯一方法是使用doseq
:
(def msgs (->> list-of-paths ;; 30K+ paths
(map mail/file->message)))
(def final (atom []))
(doseq [x result]
(swap! final conj (mail/file->message x)))
我的问题是,这是完成此过程而不一次打开成千上万个文件的最佳方法吗?我不完全理解为什么我不能使用map
返回的惰性序列。为什么最终打开大量文件。
顺便说一句,我注意到的一件事是clj-glob
并不是一个维护良好的软件包,它在调用with-open
时没有使用as-file
...
答案 0 :(得分:1)
即使您正确地打开/关闭文件,在执行程序的过程中也有可能达到内部定义的限制,以限制程序可以拥有的文件描述符的数量(这在寿命长的程序中很常见,例如作为微服务)。
您可以在此处阅读有关如何查找当前限制以及如何增加该限制的信息:https://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/