其实,这个功能是继承着文件的读写来的。
有一个需要区分的功能就是输出功能,如果使用format函数进行打印,打印的对象必须全都是字符串。如果是其他的数据格式,打印就会失败。但是,存储文件的时候这个是可以的,从我手头的教程看这个被当作了一个数据库存储的功能。
我直接手打一遍书中的例子,然后做一下简单的理解。
首先,我的全部代码如下:
;; created by Grey
;; define a global variable to save the database
(defvar *db* nil)
(defun make-cd (title artist rating ripped)
(list :title title :artist artist :rating rating :ripped ripped))
(defun add-record (cd) (push cd *db*))
(defun prompt-read (prompt)
(format *query-io* "~a: " prompt)
(force-output *query-io*)
(read-line *query-io*))
(defun prompt-for-cd ()
(make-cd
(prompt-read "Title")
(prompt-read "Artist")
;; (prompt-read "Rating")
(or (parse-integer (prompt-read "Rating") :junk-allowed t) 0)
(y-or-n-p "Ripped [y/n]")))
(defun add-cds ()
(loop (add-record (prompt-for-cd))
(if (not (y-or-n-p "Another? [y/n]: ")) (return))))
(defun dump-db()
(dolist (cd *db*)
(format t "~{~a: ~10t~a~%~}~%" cd)))
(defun save-db (filename)
(with-open-file (out filename
:direction :output
:if-exists :supersede)
(with-standard-io-syntax
(print *db* out))))
(defun load-db (filename)
(with-open-file (in filename)
(with-standard-io-syntax
(setf *db* (read in)))))
(defun dump-db-new()
(format t "~{~{~a: ~10t~a~%~}~%~}" *db*))
做一下测试:
随便录入一点信息:

值得注意的是,这个软件的健壮性还是可以的,上面我路数的时候有一个信息输入错误,程序并没有崩溃掉。
数据库的存储:

推出lisp交互之后,看一下文件变化;

可以看得到,生成了一个数据库文件。直接使用文本工具打开看看;

看得出,这个内容其实是跟lisp界面显示的信息差不多的。接下来,重新运行程序,看看数据库的加载功能。

从初始状态看,数据库没有加载的时候信息是空的。

数据库加载成功。
功能演示完了,看一下具体的实现。首先,数据库的存储,关键代码:
(defun save-db (filename)
(with-open-file (out filename
:direction :output
:if-exists :supersede)
(with-standard-io-syntax
(print *db* out))))
其实就是一个文件的写入存储,但是,这里的操作不是format而是print。看起来,这个print的功能是要更加贴近于底层的。
再看数据库的加载,关键代码:
(defun load-db (filename)
(with-open-file (in filename)
(with-standard-io-syntax
(setf *db* (read in)))))
其实,这个更加简单了,就是一个文件的读取。但是,这里有一个小小的知识点:setf,这个看着用法像是函数,但是实际上是一个宏,其作用是把第二个参数赋值为第一个参数。写到这里,我有一单点小想法,有一个有意思的功能可以做一下了,具体是什么后期实现下再说。
















