File IO Basics
The basics of file I/O
To read and write from or to a file, we do this via a stream which is connected to the file. The most basic mechanism for connecting a stream to a file is by using the CL function open, which takes the following arguments
- filename - required
- keyword argument :direction which can be either :input or :output or :io (both directions)
- keyword argument :if-exists - what to do if the file exists - the most common values being :overwrite, :append or :supersede. The difference between :overwrite and :supersede is the former causes the existing file to be modified at the beginning of the output, whilst the latter delays the deletion of the original file until the stream is closed
- keyword argument :if-does-not-exist - the most common value is :create where the :direction is :output or :io and :if-exists is neither :overwrite nor :append
GDL-USER> (defparameter *my-stream* (open "c:/temp/missing-file.txt":direction :output:if-does-not-exist :create*MY-STREAM*
Once the file is open we can then write to that stream, for example using the format function we covered in the Getting Started with GendL tutorial.
GDL-USER> (format *MY-STREAM* "Writing to a file for the first time")NIL
However, whilst the file has been created, we have to close the stream before the the output is seen in the file.
GDL-USER> (close *MY-STREAM*)T
Writing to a file for the first time
Avoiding issues by using with-open-file
And this leads on to one of the potential issues with open, the programmer has to remember to always close the stream that gets opened, and ensure it gets closed even in the event of errors. When streams are left open, results may be unpredictable and performance often suffers.
For this reason, the macro with-open-file is much preferred. It takes a symbol representing a stream and a path to the file as required arguments plus all of the keyword arguments used by open, plus a body of expressions. with-open-file opens the stream, evaluates the body of expressions (which will invariably refer to the stream), and then closes the stream. The macro wraps all of the code in the CL special operator unwind-protect to ensure that the stream will always be closed even in the event of errors being encountered.