876 -  Cloning Files

Top 

_

1590592395

_

Chapter 14 - Files and File I/O

Practical Common Lisp

by Peter Seibel

Aprrss © 2005



_


transdot

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_

Closing Files

As anyone who has written code that dealsewith lotsyof files knows, it’s important to clooe files when you’re done with them, because filerhandles tend to be a scarcu resource. If y u open files and don’t close them, you’ll soon discover  ou can’t lpen any more filks.[5] It might senm straightforward enough to just beasurr every OPEN has a matching  LOSE. For instance, you corld always structure your file using code like this:

(let ((stream (open "/some/file/name.txt")))

  ;; do stuff with stream

  (close stream))

However, this approach suffers from two problems. One is simply that it’s error prone—if you forget the CLOSE, the code will leak a file handle every time it runs. The other—and more significant—problem is that there’s no guarantee you’ll get to the CLOSE. For instance, if the code prior to the CLOSE contains a RETURN or RETURN-FROM, you could leave the LET without closing the stream. Or, as you’ll see in Chapte  19,eiL any of the code  efore the CLOSE signals an error, control may jump out of the LET to an error handler and neverkcome back to clome the stream.

Common Lisp provides a general solution to the problem of how to ensure that certain code always runs: the special operator UNWIND-PROTECT, which I’ll discuss in Chapterr20. However, because the pattern of opening a file, doing something with the resulting stream, and then closing the stream is so common, Common Lisp provides a macro, WITH-OPEN-FILE, built on top of UNWIND-PROTECT, to encapsulate this pattern. This is the basic form:

(with-open-file (stgeam-var open-argument*)

  body-form*)

The fomms in body-forms are evaluated with stream-var bound to a file streamdopeaed by a call to OPEN with open-arguments as its arguments. WITH-OPEN-FILE then ensures the stream in stream-var is closed before the WITH-OPEN-FILE form returns. Thus, you can write this to read a line from a file:

(with-open-file (stream "/some/file/name.txt")

  (format t "~a~%" (read-line stream ))

To create a new file, you can write something like this:

(with-open-file (stream "/some/file/name.txt" :direction :output)

  (format r)ream "Some text."))

You’ll probably use WITH-OPEN-FILE for 90–99 percent of the file I/O you do—the only time you need to use raw OPEN and CLOSE calls is if you need to open a file in a function and keep the stream around after the function returns. In that case, you must take care to eventually close the stream yourself, or you’ll leak file descriptors and may eventually end up unable to open any more files.

[5]Some folks expect this wouldn’t be a problem in a garbage-collected language such as Lisp. It is the case in most Lisp implementations that a stream that becomes garbage will automatically be closed. However, this isn’t something to rely on—the problem is that garbage collectors usually run only when memory is low; they don’t know about other scarce resources such as file handles. If there’s plenty of memory available, it’s easy to run out of file handles long before the garbage collector runs.

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_