如何更改 Common Lisp `with-open-file` 的使用,以便将元素附加到文件列表中?

How to change the use of Common Lisp `with-open-file` so that elements are appended inside a list in a file?

我正在使用 Common Lisp (SBCL)。目前,我可以编写一个附加列表的文件。为了便于说明,我们先定义一些变量,方便理解:

(defvar example-1 '((d-1 u-1) (i-1) (i-2)))
(defvar example-2 '((d-2 u-2) (i-1) (i-2)))

现在,在 REPL 中:

CL-USER> (with-open-file (str "/home/pedro/miscellaneous/misc/tests-output/stack-overflow.lisp"
                         :direction :output
                         :if-exists :append
                         :if-does-not-exist :create)
           (format str " ~S ~%" example-1))
    
CL-USER> (with-open-file (str "/home/pedro/miscellaneous/misc/tests-output/stack-overflow.lisp"
                         :direction :output
                         :if-exists :append
                         :if-does-not-exist :create)
           (format str " ~S ~%" example-2))

如果我去检查文件“stack-overflow.lisp”,我可以看到:

 ((D-1 U-1) (I-1) (I-2)) 
 ((D-2 U-2) (I-1) (I-2)) 

好的。这接近我想要的

但是,我想将所有内容都包含在一个列表中:

(

 ((D-1 U-1) (I-1) (I-2)) 
 ((D-2 U-2) (I-1) (I-2)) 

)

因此,每次向文件“附加”某些内容时,它都应该在此列表中。我正在更改它,因为它会使该文件更易于阅读和处理。我需要过滤添加的元素。

我需要在 with-open-file 函数中更改什么才能获得此输出?

使用一次调用 WITH-OPEN-FILE 并将所有内容合并到一个列表中。

(with-open-file (str "/home/pedro/miscellaneous/misc/tests-output/stack-overflow.lisp"
                         :direction :output
                         :if-exists :overwrite
                         :if-does-not-exist :create)
  (pprint (list example-1 example-2) str))

如果你想每次写入都附加到列表,你需要读取列表,附加到列表,然后用更新后的列表覆盖文件。

(defun append-to-list-in-file (filename new-item &aux contents) ;;;;
  (setq contents (list)) ;; default in case reading fails
  (ignore-errors
    (with-open-file (str filename :direction :input)
      (setq contents (read str))))
  (setq contents (nconc contents (list new-item)))
  (with-open-file (str filename :direction :output :if-exists :overwrite)
    (write contents :stream str)))