Working with Files

In addition to using streams to write to and read from the REPL, we can also use streams to write to and read from files.

You can create a file stream in Common Lisp in several ways. The best way is to use the with-open-file command. As you’ll see shortly, this command contains special bug-prevention features that make it safer to use than other available file commands. The following example uses with-open-file to write the string "my data" to a file named data.txt:

> (with-open-file (my-stream "data.txt" :direction :output)
      (print "my data" my-stream))

In this example, the with-open-file command binds the output stream to the name my-stream . This causes a file output stream to be created with the name my-stream. This stream will be available within the body of the with-open-file command (until the final closing bracket ), and any data we send to this stream will end up in the file named data.txt on the disk. The print command references my-stream as the destination for its output . Therefore, after running this example, you should find a new file named data.txt in the folder from which you launched CLISP. This file has the text "my data" as its content.

Specifying :output as the direction for with-open-file creates an output stream. To make this an input stream instead, we could change the direction to :input, as follows:

> (with-open-file (my-stream "data.txt" :direction :input)
     (read my-stream))
"my data"

As you can see, this causes the data—the same data written to the file in the previous example—to be read in from the file.

As you learned in Chapter 6, the print and read commands can print and read any of the basic Common Lisp data types. This functionality makes it easy to use streams to store data from your programs to the hard drive. Here is a more complicated example that writes an association list (alist) to a file:

 > (let ((animal-noises '((dog . woof)
                           (cat . meow))))
     (with-open-file (my-stream "animal-noises.txt" :direction :output)
         (print animal-noises my-stream)))
  ((DOG . WOOF) (CAT . MEOW))
 > (with-open-file (my-stream "animal-noises.txt" :direction :input)
       (read my-stream))
  ((DOG . WOOF) (CAT . MEOW))

In this example, we’re creating an association table of animals and the sounds they make. We create a new alist named animal-noises . We put keys for dog and cat into this list. Now we can write this alist to a new file called animal-noises.txt . Later, we can easily reconstitute this alist from the file .

The with-open-file command can take keyword parameters that modify its behavior. For instance, you can tell the command what to do if a file with the given name already exists. In the following example, we’ll display an error message using the :if-exists keyword parameter:

> (with-open-file (my-stream "data.txt" :direction :output :if-exists :error)
      (print "my data" my-stream))
*** - OPEN: file #P"/home/user/data.txt" already exists

Alternatively, you may simply want the existing file to be overwritten. In that case, set the :if-exists keyword parameter to :supersede, as follows:

> (with-open-file (my-stream "data.txt" :direction :output
                                         :if-exists :supersede)
      (print "my data" my-stream))
"my data"

The with-open-file command gives you a very succinct way to work with files. Unlike most programming languages, when using this command, you don’t need to open and close files manually, and you don’t need to worry about potentially messing up your files by failing to properly close them. (Actually, Common Lisp has lower-level commands for opening and closing files as well, but with-open-file packages them in a clean way that hides all the ugly details.)

image with no caption

The main purpose of with-open-file is to acquire a file resource. It takes command of the file and assumes the responsibility of closing it. In fact, even if the code inside the with-open-file throws an ugly error that stops the program dead, with-open-file will still close the file properly to make sure this resource stays intact.

Note

Common Lisp has many commands that begin with with- that will safely allocate resources in this way. These with- commands, available in the core Lisp libraries, are built with Lisp’s awesome macro system. You’ll learn more about Lisp macros, and how to create your own with- commands, in Chapter 16.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.3.167