Writing Files in Lisp

Here’s the translation of the Go code example to Lisp, formatted in Markdown suitable for Hugo:

Writing files in Lisp follows similar patterns to the ones we saw earlier for reading.

(defun check (e)
  (when e
    (error e)))

(defun main ()
  ;; To start, here's how to dump a string (or just bytes) into a file.
  (with-open-file (stream "/tmp/dat1" :direction :output :if-exists :supersede)
    (write-string "hello
lisp
" stream))

  ;; For more granular writes, open a file for writing.
  (with-open-file (f "/tmp/dat2" :direction :output :if-exists :supersede)
    ;; You can write strings as you'd expect.
    (let ((d2 "some
"))
      (write-string d2 f)
      (format t "wrote ~A bytes~%" (length d2)))

    ;; A write-string is also available.
    (let ((s "writes
"))
      (write-string s f)
      (format t "wrote ~A bytes~%" (length s)))

    ;; Force output to be written to the file.
    (force-output f)

    ;; Use with-output-to-string for buffered writing.
    (let ((buffered-string 
           (with-output-to-string (s)
             (write-string "buffered
" s))))
      (write-string buffered-string f)
      (format t "wrote ~A bytes~%" (length buffered-string)))))

(main)

Try running the file-writing code.

$ sbcl --script writing-files.lisp
wrote 5 bytes
wrote 7 bytes
wrote 9 bytes

Then check the contents of the written files.

$ cat /tmp/dat1
hello
lisp
$ cat /tmp/dat2
some
writes
buffered

In this Lisp version:

  1. We define a check function to handle errors, similar to the Go version.

  2. The main function contains our file writing operations.

  3. We use with-open-file to open files for writing, which automatically closes the file when we’re done.

  4. Instead of WriteFile, we use with-open-file with :direction :output to write a string directly to a file.

  5. We use write-string to write strings to the file, similar to Go’s Write and WriteString.

  6. force-output is used instead of Sync to ensure all buffered data is written to the file.

  7. We use with-output-to-string to create a string buffer, similar to Go’s bufio.NewWriter.

  8. Lisp doesn’t have a direct equivalent to Go’s byte slices, so we use strings instead.

Next, we’ll look at applying some of the file I/O ideas we’ve just seen to the standard input and output streams.