Reading — step 1 of 4
Learn
~2 min readPackages, Sequences, Pathnames
Common Lisp has a portable filesystem abstraction — pathnames — that work across Unix, Windows, even old VMS. The flip side: it's verbose for everyday use.
Pathnames
(make-pathname :directory '(:absolute "home" "user")
:name "data"
:type "txt")
;; → #P"/home/user/data.txt"
Fields: host, device, directory, name, type, version.
Parse from a string:
(pathname "/home/user/data.txt")
File operations
(probe-file "data.txt") ; pathname if exists, nil if not
(file-write-date "data.txt") ; universal time
(file-length stream) ; size when opened
(delete-file "data.txt")
(rename-file "old.txt" "new.txt")
Listing a directory
Not in standard Common Lisp! Use directory:
(directory "*.lisp") ; list of pathnames
(directory "src/**/*.lisp") ; recursive
Or use cl-fad (file-and-directory) or uiop:directory-files for portability:
(uiop:directory-files "src/")
Reading a file
(with-open-file (in "data.txt" :direction :input)
(loop for line = (read-line in nil :eof)
until (eq line :eof)
do (format t "~a~%" line)))
Writing a file
(with-open-file (out "output.txt"
:direction :output
:if-exists :supersede)
(format out "line 1~%")
(format out "line 2~%"))
Slurping
(defun slurp (path)
(with-open-file (in path)
(with-output-to-string (out)
(loop for line = (read-line in nil nil)
while line
do (write-line line out)))))
The uiop:read-file-string (UIOP is bundled with ASDF) is a one-liner:
(uiop:read-file-string "data.txt")
Common patterns
Append to a log file:
(with-open-file (log "app.log"
:direction :output
:if-exists :append
:if-does-not-exist :create)
(format log "~a: ~a~%"
(get-universal-time)
message))
Read a CSV-like file:
(with-open-file (in "data.csv")
(loop for line = (read-line in nil :eof)
until (eq line :eof)
collect (split-string line #\,)))
Beyond standard CL
For real-world file work, almost everyone uses:
uiop— Universal Imperative Operations Pack (ASDF-bundled)cl-fad— file and directory utilitieslocal-time— date/time handling (CL's built-in is awkward)
(uiop:read-file-lines "data.txt")
(uiop:directory-files "src/" "*.lisp")
(uiop:run-program '("git" "status") :output :string)
These are de facto standards for non-trivial code.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…