如何在SBCL / Common Lisp中序列化和加载对象

时间:2016-09-18 07:54:48

标签: serialization common-lisp sbcl

我有一个对象o,它是SBCL中X类的一个实例。

我想要一个函数write-X-object,它将o序列化为一个文件,当用load-X-object读回该文件时,生成的对象相当于o。

;; writing the object
(write-X-object o "~/tmp/o.serialized")

;; reading the object, much later, 
;; after sbcl has been exited and restarted

(setq v (read-X-object "~/tmp/o.serialized"))

o可能大约一千兆字节(或几百万个小对象的数组),结构复杂,因此想法是尽可能快地进行读写。

2 个答案:

答案 0 :(得分:4)

有三种主要方法可以做到这一点

  1. 使用打印/读取的内置工具:您可以在print-object上为您的类定义一个方法来序列化它(也许您会依赖于某些特殊变量,因此您不会打印千兆字节到repl)。然后你可以定义一个阅读器宏(对应于你用来打印你的对象的任何语法),然后保存你要做(with-open-file (x "/tmp/foo" :direction :output) (print my-object X))的对象,然后把它取回来做(with-open-file (x "/tmp/foo") (read x)。优点是这很简单。缺点是这很慢并且不节省空间。
  2. 您可以利用评论者建议的conspack等第三方序列化库。优点:读写速度相当快。缺点:您无法逐步读取大于内存的对象。
  3. 您可以重构您的类(使用MOP),以便对象可以以完全相同的格式存储在内存和磁盘上,然后使用mmap进行读/写。一个示例库是manardb。该系统还允许存储许多不同的对象。优点:无需读取/写入磁盘的开销。可以自动处理大于主存储器的对象(处理ram进/出ram)。缺点:访问对象字段的开销可能很小。请注意,使用此方法,通常可以通过使用可以通过ffi指针正确优化访问的实现以及使用专用数据结构(例如,浮点数组比通用数组好得多)来避免大部分缺点。

答案 1 :(得分:0)

就像定义方法print-object一样,我想您可以用MAKE-LOAD-FORM覆盖泛型函数defmethod

make-load-formmake-load-form-saving-slots已在HyperSpec中定义。

它们返回两种形式,然后您可以用文本将表单写入文件,尽管这可能会占用更多的磁盘空间(比较写入特定的二进制规范)。


CLiki上有一个有关序列化的页面。我认为现在可以使用某些第三方软件包。