155
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.
156
Another reason the pathname system is considered somewhat baroque is because of the inclusion of
157
Many Unix-based implementations treat filenames whose last element starts with a dot and don't contain any other dots specially, putting the whole element, with the dot, in the name component and leaving the type component NIL
.
(pathname-name (pathname '/foo/.emacs')) ==> '.emacs'
(pathname-type (pathname '/foo/.emacs')) ==> NIL
However, not all implementations follow this convention; some will create a pathname with '' as the name and emacs
as the type.
158
The name returned by FILE-NAMESTRING
also includes the version component on file systems that use it.
159
he host component may not default to NIL
, but if not, it will be an opaque implementation-defined value.
160
For absolutely maximum portability, you should really write this:
(make-pathname :type 'html' :version :newest :defaults input-file)
Without the :version
argument, on a file system with built-in versioning, the output pathname would inherit its version number from the input file which isn't likely to be right—if the input file has been saved many times it will have a much higher version number than the generated HTML file. On implementations without file versioning, the :version
argument should be ignored. It's up to you if you care that much about portability.
161
See Chapter 19 for more on handling errors.
162
For applications that need access to other file attributes on a particular operating system or file system, libraries provide bindings to underlying C system calls. The Osicat library at http://common- lisp.net/project/osicat/
provides a simple API built using the Universal Foreign Function Interface (UFFI), which should run on most Common Lisps that run on a POSIX operating system.
163
The number of bytes and characters in a file can differ even if you're not using a multibyte character encoding. Because character streams also translate platform-specific line endings to a single #Newline
character, on Windows (which uses CRLF as its line ending) the number of characters will typically be smaller than the number of bytes. If you really have to know the number of characters in a file, you have to bite the bullet and write something like this:
(with-open-file (in filename)
(loop while (read-char in nil) count t))
or maybe something more efficient like this:
(with-open-file (in filename)
(let ((scratch (make-string 4096)))
(loop for read = (read-sequence scratch in)
while (plusp read) sum read)))
164
MAKE-BROADCAST-STREAM
can make a data black hole by calling it with