Skip to content

LISP - 向流写入数据

写入数据是一项基本的 I/O 操作(Input/Output Operation)。在 Common Lisp 中,所有输出都定向到流(stream)。流是数据的来源或目标,例如控制台、文件或字符串。本教程将探讨写入数据的现代最佳实践。

Lisp 管理着几个标准流。其中最重要的输出流是 *standard-output*,它通常默认为您的终端或控制台(REPL)。

核心输出函数:选择合适的工具

Section titled “核心输出函数:选择合适的工具”

Lisp 提供了多个写入函数。关键是选择与您的意图相符的那个。

  • princ:以人类可读的格式写入对象。例如,它打印字符串时不会包含引号。用于为用户生成清晰的输出。(princ "Hello, World!") -> Hello, World!
  • print:以 Lisp 可读的格式写入对象,前面有一个换行符,后面有一个空格。它会为字符串添加引号,适用于调试或 Lisp 的 read 函数可能解析回来的输出。(print "Hello, Lisp!") -> (换行)"Hello, Lisp!"
  • write:主函数,可通过关键字参数高度定制。print 和 princ 本质上是 write 的便捷预设。当您需要对输出格式进行精细控制时,请使用 write。
  • format:最强大、最灵活的工具。它使用控制字符串和参数来创建格式化文本,类似于 C 语言中的 printf。它是编写复杂消息、报告或任何结构化文本的理想选择。

实践示例 1:使用 format 写入控制台

Section titled “实践示例 1:使用 format 写入控制台”

format 是生成结构化输出的惯用方式。第一个参数 t 将输出定向到 *standard-output*。

(let ((user "Alex")
(items-count 5))
(format t "Welcome, ~a!~%You have ~d items in your cart.~%" user items-count))
;; 指令:
;; ~a - 美观输出:以人类可读的方式打印(类似于 princ)。
;; ~d - 十进制:打印一个整数。
;; ~% - 波浪号百分号:打印一个换行符。
Welcome, Alex!
You have 5 items in your cart.

现代、安全且推荐的文件写入方式是使用 with-open-file 宏。它会自动处理文件的打开,并且至关重要的是,确保在代码块退出时流被关闭,即使发生错误也不例外。

;; 创建一个名为 'app.log' 的日志文件
(with-open-file (log-stream "app.log"
:direction :output
:if-exists :supersede
:if-does-not-exist :create)
(format log-stream "Log started at ~a~%" (get-universal-time))
(princ "Application event: User logged in." log-stream)
(terpri log-stream) ; terpri = terminate print(写入一个换行符)
(format log-stream "Log finished."))
(print "Log file 'app.log' has been written.")
Log started at 3855138000
Application event: User logged in.
Log finished.
  • 使用 with-open-file:对于文件 I/O,始终优先使用此宏,而非手动调用 open 和 close。它能防止资源泄露。
  • 缓冲(Buffering):出于效率考虑,流的输出通常是缓冲的。如果您需要确保数据立即写入(例如,在潜在崩溃前写入日志文件),请调用 (finish-output stream) 或 (force-output stream)。
  • 写入字符串:要将输出捕获到字符串而非文件或控制台,请使用 with-output-to-string 宏。示例:(with-output-to-string (s) (format s "Hello, ~a" "string")) 返回 "Hello, string"。
  • 错误处理:文件操作可能会失败(例如,磁盘已满、无权限)。在健壮的应用程序中,请将 with-open-file 包装在 handler-case 块中,以优雅地处理潜在的 file-error 条件。