Message from discussion Newbie : file handling
From: Pascal Costanza <costa...@web.de>
Subject: Re: Newbie : file handling
Date: Sat, 29 Nov 2003 16:22:16 +0100
Content-Type: text/plain; charset=us-ascii; format=flowed
X-Trace: newsreader2.netcologne.de 1070119339 25368 188.8.131.52 (29 Nov 2003 15:22:19 GMT)
NNTP-Posting-Date: Sat, 29 Nov 2003 15:22:19 +0000 (UTC)
User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5) Gecko/20031013 Thunderbird/0.3
X-Accept-Language: en-us, en
Martin Raspaud wrote:
> I'm just starting to write a lisp program for music and I want to open a
> wav file and read its content and put it into an array.
> Opening the file isn't much of a problem. The reading is more.
> The 4 first bytes of the file contain "RIFF"
> The next 4 bytes contain a 32bits integer giving the length of the file
> the next 4 bytes contain "WAVE"
> and so on.
> My question is : how do I get the length of the file with lisp ? I tried
> "read-byte" with several type specifiers, but I can't get anything...
> each time I get 4 numbers corresponding to the 4 bytes, but I want 1
> I hope anyone has an answer...
I have written the following code to read Java class files. They use
8-bit bytes to encode 16-bit, 32-bit and 64-bit values in big endian
order. I have taken the approach to load a complete class file at once
into a byte array and then decode the values from that array. The idea
was to wait for profiling the actual behavior in order to see whether a
more efficient approach is needed. However, I haven't yet gotten to that
Here is the code. Note that some Common Lisp implementations might have
serious limitations on the possible maximum size of arrays.
(defmacro with-open-class-file ((cf pathname) &body block)
"similar to with-open-file"
`(let* ((,cf (open-class-file ,pathname))
(,result (progn ,@block)))
(setf ,cf ())
(defun open-class-file (class-file)
"similar to open-file"
(with-open-file (stream class-file :element-type '(unsigned-byte 8))
(let ((cf (make-array (file-length stream)
:element-type '(unsigned-byte 8)
(read-sequence cf stream)
(setf (fill-pointer cf) 0)
(defun read1 (cf)
"read one byte from a class file"
(let ((fp (fill-pointer cf)))
(incf (fill-pointer cf))
(aref cf fp)))
(defun bytes-to-int (arr &key (start 0) (end nil) (signed nil))
"take a multibyte datum in big-endian order"
(when (null end) (setq end (length arr)))
(assert (< start end))
(let ((len (- end start))
(res (reduce (lambda (x y) (logior (ash x 8) y)) arr
:start start :end end :initial-value 0)))
(if (and signed (> len 0))
(let ((dec (expt 2 (ash len 3))))
(if (>= res (ash dec -1))
(- res (expt 2 (* len 8)))
(defun readn (cf n &key (signed nil))
"read n bytes from a class file"
(let* ((start (fill-pointer cf))
(end (setf (fill-pointer cf) (+ start n))))
(bytes-to-int cf :start start :end end :signed signed)))
The code uses only standard stuff per ANSI Common Lisp. I guess other
people probably have suggestions for improvement. (This code is already
derived from various hints I have gotten from past c.l.l postings.)
Tyler: "How's that working out for you?"
Tyler: "Keep it up, then."