求助:Lisp中JSON文件读写函数的实现与问题排查
问题分析与修复方案
早上好!让我们一步步搞定你在Lisp中实现JSON读写函数遇到的问题~
一、json-load函数的问题与修复
先看你写的两个版本的json-load,核心问题集中在变量作用域错误和参数传递逻辑错误:
- 初始版本里,
file-contents是定义在with-open-file的局部let块内,外部的(json-parse (file-contents))根本访问不到这个变量,而且这里把变量当成函数调用,语法本身就错了。 - 修改后的版本里,你调用
file-get-contents拿到了文件内容,但没有把这个内容传给json-parse,反而把文件名传了进去——json-parse需要的是JSON格式的字符串,不是文件名,这才会导致“undefined JSON object”的错误。
另外,file-get-contents里的with-open-file最好明确指定输入方向和不存在报错的行为,避免依赖默认值带来的意外。
修复后的json-load函数如下:
(defun json-load (filename) (let ((file-contents (file-get-contents filename))) (json-parse file-contents))) (defun file-get-contents (filename) (with-open-file (stream filename :direction :input :if-does-not-exist :error) (let ((contents (make-string (file-length stream)))) (read-sequence contents stream) contents)))
这个版本的逻辑是:先通过file-get-contents读取文件的完整内容字符串,再把这个字符串传给json-parse解析,完全符合你“先读文件为字符串再解析”的需求,也会在文件不存在时抛出错误。
二、json-write函数的问题与修复
你当前的json-write函数里,(pprint (json out))是完全错误的——json不是合法的函数调用,而且你漏掉了最关键的一步:把Lisp的JSON对象序列化成符合JSON语法的字符串。
假设你使用的JSON库提供了类似json-stringify的序列化函数(比如常见的cl-json库用json:encode-json-to-string),修复后的函数可以这样写:
(defun json-write (json filename) (with-open-file (out filename :direction :output :if-exists :overwrite :if-does-not-exist :create :external-format :utf-8) ; 建议指定UTF-8编码,避免中文等字符乱码 (write-string (json-stringify json) out) ; 替换成你实际使用的序列化函数 filename)) ; 按照需求返回传入的文件名
如果你的JSON库支持直接向输出流序列化(比如cl-json的json:encode-json),也可以直接写入流:
(defun json-write (json filename) (with-open-file (out filename :direction :output :if-exists :overwrite :if-does-not-exist :create :external-format :utf-8) (json:encode-json json out) ; 适配cl-json库的写法 filename))
对你的两个问题的解答
- 你的函数是否部分正确?
json-load的整体思路(读文件内容→解析)是对的,但变量作用域、参数传递的逻辑完全错误;json-write里的with-open-file参数设置(输出方向、覆盖/创建规则)是正确的,但核心的序列化写入部分完全不符合要求。
- 如何将JSON对象以JSON语法写入文件?
- 核心步骤是:先利用JSON库的序列化函数,把Lisp中的JSON对象转换成标准JSON格式的字符串(或者直接写入输出流),再通过
write-string或者库提供的流写入方法,把内容写入到打开的文件流中。
- 核心步骤是:先利用JSON库的序列化函数,把Lisp中的JSON对象转换成标准JSON格式的字符串(或者直接写入输出流),再通过
测试预期用法
修复后,你预期的调用逻辑就能正常工作了:
CL-PROMPT> (json-load (json-write '(json-obj #| stuff |#) "foo.json")) ; 会返回对应的(json-obj #| stuff |#)对象,前提是你的序列化/反序列化函数能正确处理这个对象
内容的提问来源于stack exchange,提问作者Giuseppe Giubaldo
相关产品推荐
相关产品推荐

