退出而不丢失缓存的输出

时间:2018-10-18 06:40:09

标签: common-lisp

我正在尝试将一个功能添加到正在编写的程序中,该功能可以将打印到控制台的所有内容也添加到日志文件中。这可以通过广播流来完成。问题在于该程序可能还需要从叶函数中突然退出,而当我这样做时,不会创建日志文件。这是我到目前为止的内容:

(catch 'quit
  (with-open-file (log-stream "log.txt" 
                   :direction :output 
                   :if-exists :supersede 
                   :if-does-not-exist :create)
    (let ((*standard-output*
            (make-broadcast-stream *standard-output* log-stream)))
      (format t "abc~%")
      (throw 'quit nil))))

当我运行以上代码(SBCL 1.4.2,Windows 7)时,未创建文件log.txt。如果将(throw 'quit nil)替换为(quit),也是如此。但是,如果我完全删除了这一行,只是通过退出文件末尾让程序退出,则日志文件的确创建正确,这表明这是一个缓存问题。

那是正确的诊断吗?如果是这样,是否有一种方法可以告诉编译器不要缓存该文件,或者退出而不是写入缓存的数据而不是退出?

1 个答案:

答案 0 :(得分:8)

这是WITH-OPEN-FILE标准中描述的行为:

  

如果正在创建新的输出文件   写入,并且控制异常退出,文件被中止并且文件系统被保留,   尽可能,好像从未打开过文件。

以下内容将明确关闭文件:

(catch 'quit
  (with-open-file (log-stream "/tmp/log.txt" 
                   :direction :output 
                   :if-exists :supersede 
                   :if-does-not-exist :create)
    (let ((*standard-output* (make-broadcast-stream *standard-output* log-stream)))
      (unwind-protect (progn
                        (format t "abc~%")
                        (throw 'quit nil))
        (finish-output)
        (close log-stream :abort nil)))))

:abort nil的值是默认值,为便于回答,此处将其显式表示。