Книга: Practical Common Lisp

Closing Files

Closing Files

As anyone who has written code that deals with lots of files knows, it's important to close files when you're done with them, because file handles tend to be a scarce resource. If you open files and don't close them, you'll soon discover you can't open any more files.[155] It might seem straightforward enough to just be sure every OPEN has a matching CLOSE. For instance, you could 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 Chapter 19, if any of the code before the CLOSE signals an error, control may jump out of the LET to an error handler and never come back to close 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 Chapter 20. 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 (stream-var open-argument*)
body-form*)

The forms in body-forms are evaluated with stream-var bound to a file stream opened 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 stream "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.

Оглавление книги


Генерация: 1.196. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз