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

Gwa*_*Kim 2 file-io closures state generator common-lisp

我正在寻找一种方法从一个时间读取几个文件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)))
Run Code Online (Sandbox Code Playgroud)

做得很好,逐行追加结果字符串或s表达式.(我不知道 - 也许这不是最有效的方式?).

前段时间,我要求一个宏打开尽可能多的文件with-open-file,我可以从正文中访问我可以创建和给出的流变量的所有文件.然而,由于打开输入文件和输出文件的数量是可变的,也许它是非常容易的设计调用每个文件这样的呼叫者-打开它们-到达正确位置-写入或读取-然后再次关闭, 我想.

对于输出,给定的函数完成工作.但是,对于输入,我很想有我调用它,其每次的功能,读取下一个口齿不清表达(S-表达),并有一种记忆的地方读取文件中的最后一次,每次我调用它 - 重新打开文件并知道在哪里读取 - 并返回值 - 下次读取并返回下一个值等.类似于迭代器上的Python生成器 - 它产生序列中的下一个值.

我想通过表达式处理 - 读入 - 文件表达式 - 以减少内存使用量.

你会如何攻击这样的任务?或者你有一个好的策略?

Rai*_*wig 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))))) 
Run Code Online (Sandbox Code Playgroud)

用法示例:

(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
Run Code Online (Sandbox Code Playgroud)

然后编写一个方法来检查新的s表达式是否可用.等等.