在Common Lisp中逐行读取文件(低内存)

时间:2018-11-29 17:19:56

标签: file-io closures common-lisp generator state

我正在寻找一种同时读取多个文件的1 s表达式(数据列表)的方法。

问题在于文件很大-数百兆或千兆字节。而且我需要RAM来进行计算。

对于输出文件,

(defun add-to-file (process-result file-path)
  (with-open-file (os file-path :direction :output
                                :if-exists :append
                                :if-does-not-exist :create)
    (print process-result os)))

可以很好地完成一行结果字符串或s-expression的追加。 (我不知道-也许这不是最有效的方法?)。

前段时间,我请求一个宏,该宏可以使用with-open-file打开任意数量的文件,并且可以从正文访问可以创建和提供其流变量的所有文件。但是,由于打开的输入文件和输出文件的数量是可变的,因此设计可能更容易用这样的调用程序来调用每个文件-将它们打开-移至正确的位置-写入或读取-然后再次将其关闭,我想。

对于输出,给定的功能完成任务。 但是,对于输入,我希望有一个函数,每次我调用它时,都读取下一个lisp表达式(s-expression),并具有某种内存,以便在文件中以及我每次调用它时最后一次读取它-重新打开文件并知道要读取的位置-并返回值-下次读取并返回下一个值等。 类似于通过迭代器生成的Python生成器-生成序列中的下一个值。

我要处理-读入-逐个表达式的文件表达式-以使内存使用最少。

您将如何攻击此类任务?还是您有个不错的策略?

1 个答案:

答案 0 :(得分:6)

素描:

制作一个结构或类,该结构或类存储最后读取的位置。

(defstruct myfile
  path
  (last-position 0))

(defmethod next-expression ((mf myfile))
  (with-open-file (s (myfile-path mf) :direction :input)
    (file-position s (myfile-last-position mf))
    (prog1
        (read s)
      (setf (myfile-last-position mf) (file-position s))))) 

用法示例:

(defparameter *mf1* (make-myfile :path (pathname "/foo/bar.sexp")))

(print (next-expression *mf1*)) ;; get first s-expr from file
;; do sth else
(myfile-last-position *mf1*)  ;; check current position
;; do sth else
(print (next-expression *mf1*)) ;; gives next s-expr from file

然后编写一种方法来检查是否有新的s表达式。等等