s c h e m a t i c s : c o o k b o o k

/ Cookbook.IdiomSerializeToFile

This Web


WebHome 
WebChanges 
TOC (with recipes)
NewRecipe 
WebTopicList 
WebStatistics 

Other Webs


Chicken
Cookbook
Erlang
Know
Main
Plugins
Sandbox
Scm
TWiki  

Schematics


Schematics Home
Sourceforge Page
SchemeWiki.org
Original Cookbook
RSS

Scheme Links


Schemers.org
Scheme FAQ
R5RS
SRFIs
Scheme Cross Reference
PLT Scheme SISC
Scheme48 SCM
MIT Scheme scsh
JScheme Kawa
Chicken Guile
Bigloo Tiny
Gambit LispMe
GaucheChez

Lambda the Ultimate
TWiki.org

Serialize Data to File

Problem

You want to write data to a file such that when you eval that file that data is recreated.

Solution

Use the functions provided by the pconvert library to convert data into a format, that when read, will recreate the data. For example, the print-convert function converts data to quasi-quoted form:

> (require (lib "pconvert.ss"))
> (define data '(1 2 3 #(a b)))
> (print-convert data)
(quasiquote (1 2 3 #2(a b)))
> (eval (print-convert data))
(1 2 3 #2(a b))
> (equal? (eval (print-convert data)) data)
#t
> (eq? (eval (print-convert data)) data)
#f

Discussion

You might wonder we don't just use write and read instead of print-convert. There are two reasons for this. Firstly, the range of data that can be represented by print-convert is greater than that that can be represented by write. See, for instance, StructuresReadingAndWriting which discusses reading and writing structures using print-convert.

More importantly print-convert=ed data can be intermingled with program code.  For example, if we have the list ='(+ 1 2) then if we write and eval this data we get the value 3. However if we first print-convert the data and then eval it we get the back the original list:

> (define data '(+ 1 2))
> (write data)
(+ 1 2)
> (print-convert data)
`(+ 1 2)
> (let ((port (open-output-string)))
    (write data port)
    (eval (read (open-input-string (get-output-string port)))))
3  
> (eval (print-convert data))
(+ 1 2)

This allows, for example, programmatic configuration files that are a mixture of code and print-converted data. This idea is sometimes known as an Active File. For example:

> (eval `(map + ,(print-convert '(1 2 3)) ,(print-convert '(3 4 5))))
(4 6 8)

Two convenience functions to write and read (eval) files are:

;; write-converted : any string -> #void
;;
;; Write data to a file in print converted format, such that
;; when the file is evaled the data will be recreated.  Note
;; that any existing contents of the file are overwritten
(define (write-converted data filename)
  (with-output-to-file filename
    (lambda ()
      (write (print-convert data)))
    'replace))

;; read-converted : filename -> data
;;
;; Read print converted data from a file.
(define (read-converted filename)
  (with-input-from-file filename
    (lambda ()
      (eval (read)))))

In use:

> (write-converted '(1 2 3 #(a b)) "test.txt")
> (read-converted "test.txt")
(1 2 3 #2(a b))

Note that load can take the place of read-converted in most situations. Load will eval all expressions in a file, while read-converted will only eval the first. In this way read-converted is the mirror of write-converted, which only writes a single expression to a file.

To create human-readable output (for instance, in configuration files) the pretty-print function in the pretty.ss library comes in handy:

> (require (lib "pretty.ss"))
> (pretty-print (print-convert '(some (complex data) that (we (would like to (span))) a (number of lines (so that it is) (human readable)))))
`(some
  (complex data)
  that
  (we (would like to (span)))
  a
  (number of lines (so that it is) (human readable)))

See IdiomPrettyPrint? for more information.

Finally if using eval you should be careful that you protect your code and the user's computer against malicious code. See DynamicUntrustedEval for information on how to do this.

See Also

A number of recipes are mentioned in the discussion:


Comments about this recipe

Integrated all the comments into the text.

-- NoelWelsh - 23 Dec 2004

Contributors

-- NoelWelsh

-- DanielSilva

-- JensAxelSoegaard

CookbookForm
TopicType: Recipe
ParentTopic: IdiomRecipes
TopicOrder: 999

 
 
Copyright © 2004 by the contributing authors. All material on the Schematics Cookbook web site is the property of the contributing authors.
The copyright for certain compilations of material taken from this website is held by the SchematicsEditorsGroup - see ContributorAgreement & LGPL.
Other than such compilations, this material can be redistributed and/or modified under the terms of the GNU Lesser General Public License (LGPL), version 2.1, as published by the Free Software Foundation.
Ideas, requests, problems regarding Schematics Cookbook? Send feedback.
/ You are Main.guest