Subject: Re: reading a file into a string From: Erik Naggum <erik@naggum.net> Date: Sat, 02 Feb 2002 03:52:26 GMT Newsgroups: comp.lang.lisp Message-ID: <3221610744163603@naggum.net> * Dr. Edmund Weitz | I want to read a whole (text) file into a string. And I wonder what | would be the best way to do it. The function is named file-contents in Allegro CL and is based on an earlier version of mine, which goes like this: (defun file-contents (pathname &rest open-arguments) "Map the current contents of the file named by PATHNAME into a vector, which is returned. OPEN-ARGUMENTS is a list of arguments passed to OPEN; it should not include a :DIRECTION argument. An :ELEMENT-TYPE argument also specifies the type of the returned vector. Returns NIL if the file does not exist and :IF-DOES-NOT-EXIST is NIL." (with-open-stream (stream (apply #'open pathname :direction :input open-arguments)) (when stream (let ((buffer (make-array (file-length stream) :element-type (stream-element-type stream)))) (if (= (read-sequence buffer stream) (length buffer)) buffer (error 'file-error :format-control "Incomplete READ-SEQUENCE from ~S." :format-arguments (list (pathname stream)) :pathname (pathname stream))))))) (defun (setf file-contents) (vector pathname &rest open-arguments) "Make the contents of the file named by PATHNAME become that of VECTOR, which is returned. OPEN-ARGUMENTS is a list of arguments passed to OPEN; it should not include either a :DIRECTION or an :ELEMENT-TYPE argument. Does nothing and returns NIL if the file exists and :IF-EXISTS is NIL. :IF-EXISTS defaults to :SUPERSEDE." (with-open-stream (stream (apply #'open pathname :direction :output :element-type (array-element-type vector) (append open-arguments '(:if-exists :supersede)))) (when stream (write-sequence vector stream)))) Allegro CL has very strong support for various external-formats, so if you specify (or default to) characater as the element type, this may do some work between the read system call and read-sequence, so although it is very fast and efficient, it is hard to beat a byte-for-byte copy -- check which external-formats are available and apply If you want byte-for-byte copies, use (unsigned-byte 8) as the element-type. The portable way to convert between (unsigned-byte 8) and character is to use (map #'string #'code-char <byte-vector>), but you can usually find a way to hack the type system so such a byte vector turns into a string, but this is not portable, of course. Please remember that element-type and external-format are available keyword arguments to open. | 2. Is there an ANSI-compliant solution that is comparable in | performance? The above should be. Notice that file-length is a standard function, but it applies to a stream, not to pathnames. /// 2002-02-02 -- In a fight against something, the fight has value, victory has none. In a fight for something, the fight is a loss, victory merely relief.