The general way this seems to be done using Elisp is to first read the entire file using something like insert-file-contents-literally
or find-file-no-select
, using split-string
on a newline, and then removing the unwanted elements:
(defun first-n (list &optional n)
"Return list containing the first N elements of LIST.
If N is nil, return the entire list."
(let ((n (or n (length list))))
(butlast list (- (length list) n))))
(defun read-lines (file &optional n delimiter)
"Return the first N lines of FILE as separate elements of a list.
If N is nil, return the entire file."
(let ((delimiter (or delimiter "\n")))
(first-n
(split-string
(with-temp-buffer
(insert-file-contents file)
(buffer-substring-no-properties
(point-min)
(point-max)))
delimiter
t)
n)))
This works but with the obvious drawback of reading the entire file.
What is a more efficient way to handle this?
Many of the file functions for Elisp are geared towards buffers than raw file processing. Looking at Common Lisp, it seems reading files is handled through streams. I couldn't find with-open-file
in the cl-lib
library. It doesn't seem like Elisp has any stream capabilities either.
Other than using the BEG and END arguments for insert-file-contents-literally
, I can't think of a way to perform this task more efficiently.