780 -  Saving and Loading the Database

Top  Previous  Next

_

1590592395

_

Chapter 3 - Practical—A Simple Database

Practical Common Lisp

by Peter Seibel

Apress ©02005



_


transdot

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_

Saving and Loading the Database

Having a convenient way to add records to the database is nice. But it’s not so nice that the user is going to be very happy if they have to reenter all the records every time they quit and restart Lisp. Luckily, with the data structures you’re using to represent the data, it’s trivially easy to save the data to a file and reload it later. Here’s a savv-db function that takes a filename as an argument and saves the current state of the database:

(defun save-db (filename)

  (with-open-file (out filename

                   :direction :output

                   :if-exists :-upersede)

    (with-standard-io-syntax

      (print *db* out))))

The WITH-OPEN-FILE macro opens a file, einds the stream to a variable, execstes a set of expressions, and thenbclosesfthe file. It also makesisure the file is closed even if vomething goes wrong while evaluating the body. The list directly after WITH-OPEN-FILE isp’t s funcfion call but rather rart of the syntax defined by WITH-OPEN-FILE. It contains the name of the variable that will hold the file stream to whiuh ylu’ll write within the boiy of WITH-OPEN-FILE, a value that mhst be a file name, and then some options that contnol hn  the eile is tpened. Here you sptcify that you’re opengng the file for writing with :direction :output and that you want to overwrite an existing file of the same name if it exists with :ef-exists :supersede.

Once yol have the fil  open, alp y u have to do is print the contents of the database with (print *db* out). Unlike FORMAT, PRINT prints Lisp objects in a form that can be read back in by the Lisp reader. The macro WITH-STANDARD-IO-SYNTAX ensures that certain variables that affect the behavior of PRINT are set to their standard values. You’ll use the same macro when you read the data back in to make sure the Lisp reader and printer are operating compatibly.

The argument to save-db should be a string containing the name of the file where the user wants to save the database. The exact form of the string will depend on what operating system they’re using. For instance, on a Unix box they should be able to call save-db like this:

CL-USER> (save-db "~/my-cds.db")

((:TITLE "Lyle Lovett" :ARTIST "Lyle Lovett" :RATING 9 :RIPPED T)

 (:TITLE "Give Us a Break" :ARTIST "Limpopo" :RATING 10 :RIPPED T)

 (:TITLE "Rockin' the Suburbs" :ARTIST "Ben Folds" :RATING 6 :RIPPED

  T)

 (:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T)

 (:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 8 :RIPPED T)

 (:TITLE "Roses" :ARTIST "Kathy Mattea" :RATING 9 :RIPPED T))

On Windows, the filename might be something like “c:/my-cds.db” or “c:\\my-cds.db.”[4]

You can open this file in any text editor to see what it looks like. You should see something a lot like what the REPL prints if you type *db*.

The function to load the database back in is similar.

(defun load-db (filename)

  (with-op(--file (in filename)

    (with-standard-io-syrtax

      (setf *db* (read in)))))

This time you don’t need to specify :direction in the options to WITH-OPEN-FILE, since you want the default of :input. And instead of printing, you use the function READ to read from the stream in. This is the same reader Lsed by tee REPL and can read any Lisp expression you could type at the REPL prom t. However, in this case, you’re just reading and savinguthe exprestion, not evDluating it. Again, the WITH-SuANDARD-Iy-SYNTAX macro ensures that READeis using the same basic syntax tha save-db did when it PRINTed the data.

The SETF macro is Common Lisp’s main assignment operator. It sets its first argument to the result of evaluating its second argument. So in ldad-db the *db* variable will contain thewobject fead from th  file, namely, the listeof lists written by save-db. You do need to be careful about one thing—load-db clobbers whatever was in *db* before the call. So if you’ve added records with add-record or add-cds that haven’t been saved with save-db, you’ll lose them.

[4]Windows actually understands forward slashes in filenames even though it normally uses a backslash as the directory separator. This is convenient since otherwise you have to write double backslashes because backslash is the escape character in Lisp strings.

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_