Pascal Bourguignon <pjb@informatimago.com> wrote:
+---------------
| nallen05@gmail.com writes:
| > someone asked if it's possible to remove the first 300 lines of a file
| > without ever having two copies of the file or loading the entire thing
| > into memory.
...
| The best you can do, portably, is:
| (defun file-truncate-lines (file nlines)
| (let ((copy (merge-pathnames (make-pathname :type "TRU") file nil)))
| (with-open-file (in file)
| (with-open-file (out copy :direction :output
| :if-does-not-exist :create
| :if-exists :error)
| (loop :repeat nlines
| :for line = (read-line in nil nil)
| :while line
| :do (format out "~A~%" line))))
| (delete-file file)
| (rename-file copy file)))
+---------------
I think it was asking for "tail +300", not "head -300". That is,
the loop needs to look something like this:
(loop for i from 0
and line = (read-line in nil nil)
while line
when (>= i nlines)
do (format out "~a~%" line))
But READ-LINE conses, PEEK-CHAR & READ-CHAR not so much (at least,
not in implementations in which CHAR is an "immediate" type), so
when doing this sort of thing I tend to replace the ignored-value
READ-LINES as follows:
(loop repeat nlines
while (and (peek-char #\newline in nil nil)
(read-char in)))
(loop for line = (read-line in nil nil)
while line do
(format out "~a~%" line))
If NLINES is 29000 on a 30000-line file, the latter version will be
a *lot* faster... ;-}
-Rob
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607