LISP - 从流读取数据
Lisp - 从流中读取数据
Section titled “Lisp - 从流中读取数据”输入/输出(I/O)是任何应用程序的基础。在 Common Lisp 中,I/O 通过 streams(流)处理。本教程探讨了从流中读取数据的现代和安全方法,例如从控制台读取用户输入或从文件中读取内容。
流读取工具包
Section titled “流读取工具包”Common Lisp 提供了一套分层的读取函数,从单个字符到整个 Lisp 对象。
- 表达式级别:
read:从流中解析一个完整的 Lisp S-expression(S表达式)。它可以读取数字、字符串、符号和列表。安全警告:仅在信任的输入中使用read,因为它在解析#.(+ 2 2)等表达式时可以执行代码。 - 行级别:
read-line:读取字符字符串,直到遇到换行符。这是读取文本数据最常见的方式之一。 - 字符级别:
read-char:从流中读取单个字符。适用于细粒度解析。 - 二进制级别:
read-byte:从二进制流中读取单个字节。对于处理图像或可执行文件等文件至关重要。 - 预读:
peek-char:允许您查看流中的下一个字符,但不消耗它。这对于做出解析决策很有用。
最佳实践:使用 with-open-file 进行安全文件处理
Section titled “最佳实践:使用 with-open-file 进行安全文件处理”手动打开和关闭文件容易出错。如果在文件打开后但在关闭前发生错误,文件句柄可能会悬空。with-open-file 宏通过保证文件被关闭(即使发生错误)来健壮地处理这种情况。您应该始终优先使用 with-open-file。
示例:逐行读取文件
Section titled “示例:逐行读取文件”假设我们有一个名为 config.txt 的文件,内容如下:
host=localhostport=8080user=admin以下是现代、安全的读取和处理方式:
(defun process-config-file (path) "Reads a configuration file and prints its contents." (with-open-file (stream path :direction :input :if-does-not-exist :error) (format t "--- Reading config from ~a ---~%" path) (loop for line = (read-line stream nil :eof) until (eq line :eof) do (format t "Read line: ~s~%" line)) (format t "--- End of file ---~%")))
;; To run it:;; (process-config-file "config.txt")--- Reading config from config.txt ---Read line: "host=localhost"Read line: "port=8080"Read line: "user=admin"--- End of file ---with-open-file:将打开的文件流绑定到变量stream。当块退出时,它会自动关闭流。:direction :input:指定我们以读取模式打开文件。:if-does-not-exist :error:这是一个安全的默认设置。如果文件未找到,则会发出错误信号。read-line stream nil :eof:这是一个关键的习惯用法。第一个nil意味着我们不希望在文件末尾(EOF)时出现错误。第二个参数:eof是我们选择的在文件末尾到达时返回的特殊符号。这比检查nil更健壮,因为在某些情况下nil可能是一个有效的空行。loop ... until (eq line :eof):循环继续,直到read-line返回我们特殊的:eof符号。
高级错误处理
Section titled “高级错误处理”Lisp 的条件系统(Condition System)比传统的异常处理更强大。您可以使用 handler-case 来优雅地处理特定错误,例如文件未找到。
(defun safe-read-config (path) (handler-case (process-config-file path) (file-error (c) (format *error-output* "Error: Could not open file ~a. Details: ~a~%" path c) nil))) ;; Return nil on failure
;; (safe-read-config "non-existent-file.txt")Error: Could not open file non-existent-file.txt. Details: The file non-existent-file.txt does not exist.