[alexandria-devel] Proposed addition of temporary file creation utilities
Hans Hübner
hans.huebner at gmail.com
Sun Apr 22 13:35:45 UTC 2012
Hi,
following up on an IRC discussion yesterday, I am proposing the
addition of the OPEN-TEMPORARY function and WITH-OPEN-TEMPORARY-FILE
macro below (and on http://paste.lisp.org/display/129090#14). It
implements functionality that is commonly required, but that is not
available in any other library in a portable fashion. osicat has been
suggested, but it does not implement temporary file handling on
Windows.
This posting is to determine whether there is opposition regarding
inclusion in Alexandria. I'll re-post as a proper patch including
symbol exports when there is agreement to include it.
-Hans
(in-package :alexandria)
(defparameter *default-temporary-directory* #P"/tmp/")
(eval-when (:load-toplevel :execute)
(when (and (null (logical-pathname-translations "TEMPORARY-FILES"))
(probe-file *default-temporary-directory*))
(setf (logical-pathname-translations "temporary-files") `(("*.*.*"
,*default-temporary-directory*)))))
(defparameter *max-tries* 10000)
(defun generate-random-name (prefix)
(format nil "~A-~36R-~36R" prefix (random 100000000)
(get-internal-real-time)))
(define-condition cannot-create-temporary-file (error)
((directory :initarg :directory)
(prefix :initarg :prefix)
(type :initarg :type)
(max-tries :initarg :max-tries))
(:report (lambda (condition stream)
(with-slots (directory prefix type max-tries) condition
(format stream "cannot create temporary file in
directory ~A with template ~A.~A, giving up after ~D attempt~:P"
(translate-logical-pathname directory)
prefix type max-tries)))))
(defun open-temporary (&rest open-arguments
&key
type
(prefix "temp")
(directory #P"TEMPORARY-FILES:")
(generate-random-name 'generate-random-name)
(max-tries *max-tries*)
&allow-other-keys)
"Create a file with a randomly generated name and return the opened
stream. The generated pathname consists of the PREFIX with a
pseudo-random suffix. Its type will be TYPE. Temporary files are
generated in DIRECTORY which defaults to the logical pathname
temporary TEMPORARY-FILES:, which must be properly set up.
The name of the temporary file can be accessed calling the PATHNAME
function on STREAM. For convenience, the temporary file is opened
on the physical pathname, i.e. the pathname translation is
performed before opening the stream.
GENERATE-RANDOM-NAME can be passed to override the default function
that transforms PREFIX into a pseudorandom file name. It needs to
accept one argument, the PREFIX string passed, and return the
generated file name.
In order to create a unique file name, OPEN-TEMPORARY may loop
internally up to MAX-TRIES times before giving up and signalling a
CANNOT-CREATE-TEMPORARY-FILE condition."
(loop thereis (apply #'open
(translate-logical-pathname (make-pathname
:name (funcall generate-random-name prefix)
:type type
:defaults directory))
:direction :output
:if-exists nil
(remove-from-plist open-arguments :type prefix
directory generate-random-name max-tries))
repeat max-tries
finally (error 'cannot-create-temporary-file
:directory directory
:prefix prefix
:type type
:max-tries max-tries)))
(defmacro with-open-temporary-file ((stream &rest args) &body body)
"Create a temporary file using OPEN-TEMPORARY with ARGS and run BODY
with STREAM bound to the temporary file stream. See OPEN-TEMPORARY
for permitted options."
`(with-open-stream (,stream (open-temporary , at args))
, at body))
More information about the alexandria-devel
mailing list