The power of streams comes from the ability to associate a stream with a file, a device (such as keyboard, display, or network), or a memory buffer. Program I/O can be directed at will by simply creating the appropriate type of stream for your program to use. The I/O implementation is abstracted away by the stream so your program won't have to be concerned with low-level details.
Creating streams on files
The OPEN
function creates a
FILE-STREAM
. Keyword arguments determine attributes of
the stream (:DIRECTION
, :ELEMENT-TYPE
, and
:EXTERNAL-FORMAT
) and how to handle exceptional
conditions (:IF-EXISTS
and
:IF-DOES-NOT-EXIST
). If OPEN
is successful
it returns a stream, otherwise it returns NIL
or
signals an error.
Keyword Value Stream Direction
---------- ------- -----------------------------
:DIRECTION :INPUT input (default)
:DIRECTION :OUTPUT output
:DIRECTION :IO input & output
:DIRECTION :PROBE none, returns a closed stream
Keyword Value Action if File Exists
---------- ------------------ ---------------------------------------
:IF-EXISTS NIL return NIL
:IF-EXISTS :ERROR signal an error
:IF-EXISTS :NEW-VERSION next version (or error)
:IF-EXISTS :RENAME rename existing, create new
:IF-EXISTS :SUPERSEDE replace file upon CLOSE
:IF-EXISTS :RENAME-AND-DELETE rename and delete existing, create new
:IF-EXISTS :OVERWRITE reuse existing file (position at start)
:IF-EXISTS :APPEND reuse existing file (position at end)
Keyword Value Action if File Does Not Exist
------------------ ------- -----------------------------
:IF-DOES-NOT-EXIST NIL return NIL
:IF-DOES-NOT-EXIST :ERROR signal an error
:IF-DOES-NOT-EXIST :CREATE create the file
Keyword Value Element Type
------------- -------------- ------------------------
:ELEMENT-TYPE :DEFAULT character (default)
:ELEMENT-TYPE 'CHARACTER character
:ELEMENT-TYPE 'SIGNED-BYTE signed byte
:ELEMENT-TYPE 'UNSIGNED-BYTE unsigned byte
:ELEMENT-TYPE character subtype character subtype
:ELEMENT-TYPE integer subtype integer subtype
:ELEMENT-TYPE other implementation-dependent
Keyword Value File Format
---------------- -------- ------------------------
:EXTERNAL-FORMAT :DEFAULT default (default)
:EXTERNAL-FORMAT other implementation-dependent
Once you've opened a stream, you can use it with appropriate input or output functions, or with queries that return attributes of either the stream or the file. The following queries can be applied to all kinds of streams. All of these accept a stream argument:
Function Returns
-------------------- -----------------------------------------------------
INPUT-STREAM-P true if stream can provide input
OUTPUT-STREAM-P true if stream can accept output
OPEN-STREAM-P true if stream is open
STREAM-ELEMENT-TYPE the type specifier for stream elements
INTERACTIVE-STREAM-P true if stream is interactive (e.g. keyboard/display)
These queries can be applied to file streams. These also accept a stream argument:
Function Returns
-------------------- -----------------------------------------------------
STREAM-EXTERNAL-FORMAT implementation-dependent
FILE-POSITION current file offset for read or write, or NIL
FILE-LENGTH length of stream, or NIL
FILE-POSITION
returns a byte offset within the stream.
This is an exact count for streams of integer subtypes (see below for
further description of binary I/O). For streams of character subtypes,
the position is guaranteed only to increase during reading or writing;
this allows for variations in text record formats and line terminators.
FILE-POSITION
can also be called with a second argument to
change the file offset for the next read or write. When used for this
purpose, FILE-POSITION
returns true when it succeeds.
You should always close a stream when you're done using it
(except for the interactive streams provided for you use by Lisp,
such as *STANDARD-INPUT*
,
*STANDARD-OUTPUT*
, and *TERMINAL-IO*
). The
"open, process, close" pattern is very common, so Lisp provides macros
to make the pattern both easy to code and error-free.
WITH-OPEN-FILE
is tailored for file streams. Its arguments
are a variable to be bound to the stream, a pathname, and (optionally)
keyword arguments suitable for OPEN
. The stream is always
closed when control leaves the WITH-OPEN-FILE
form.
(with-open-file (stream "my-file.dat" :direction :input)
... do something using stream ...)
WITH-OPEN-STREAM
expects a variable name and a form to
be evaluated; the form should produce a stream value or NIL
.
This macro is commonly used with constructors for specialty streams,
such as MAKE-BROADCAST-STREAM
, MAKE-ECHO-STREAM
,
MAKE-TWO-WAY-STREAM
, MAKE-CONCATENATED-STREAM
,
and MAKE-SYNONYM-STREAM
.
Finally we have an example ready to run
(defun copy-a-file ()
"Read a file and copy to"
(let ((value-from-read-byte nil)
(origin-path "/tmp/my-file.jpg")
(new-path "/tmp/my-new-file.jpg"))
(with-open-file (origin-file origin-path :direction :input :element-type 'unsigned-byte)
(with-open-file (new-file new-path :direction :output :element-type 'unsigned-byte :if-exists :supersede)
;;Here we read the origin file and writing into the new file
(loop
;; exit when get :eof (end of file)
(when (equal value-from-read-byte :eof) (return nil))
;; reading the data
(setf value-from-read-byte (read-byte origin-file nil :eof))
;; writing the data; in other words copy a file
(unless (equal value-from-read-byte :eof)
(write-byte value-from-read-byte new-file)))))))
#lisp #streams