[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