Как я могу прочитать содержимое файла в список в Лиспе? - PullRequest
10 голосов
/ 28 сентября 2010

Я хочу прочитать содержимое файла в список. Некоторые из моих попыток до сих пор были -

(defun get-file (filename)
  (let ((x (open filename)))
    (when x
      (loop for line = (read-line x nil)
     while line do (list line)))
    (close x)))

(defun get-file (filename)
  (let ((x (open filename :if-does-not-exist nil)) (contents (list nil)))
    (when x
      (loop for line = (read-line x nil)
     while line do (cons contents line)))
    (close x) contents))

(defun get-file (filename)
  (let ((x (open filename :if-does-not-exist nil)) (contents nil))
    (when x
      (loop for line = (read-line x nil)
     while line do (append contents line)))
    (close x) contents))

Ничего из этого не сработало. Может кто-нибудь сказать мне путь? Или еще лучше - как поместить все содержимое в массив?

Ответы [ 3 ]

15 голосов
/ 28 сентября 2010

Как насчет

(defun get-file (filename)
  (with-open-file (stream filename)
    (loop for line = (read-line stream nil)
          while line
          collect line)))
10 голосов
/ 02 октября 2010

Где проблемы?

(defun get-file (filename)
  (let ((x (open filename)))
    (when x
      (loop for line = (read-line x nil)
            while line
            do (list line)))    ; <-- you are not collecting, just doing
    (close x)))                 ; <- the function returns the value of CLOSE

(defun get-file (filename)
  (let ((x (open filename :if-does-not-exist nil))
        (contents (list nil)))
    (when x
      (loop for line = (read-line x nil)
            while line
            do (cons contents line)))  ; <-- again, the cons goes nowhere
    (close x) contents))               ; <-- CONTENTS has never been changed

(defun get-file (filename)
  (let ((x (open filename :if-does-not-exist nil))
        (contents nil))
    (when x
      (loop for line = (read-line x nil)
            while line
            do (append contents line)))  ; <- again the result goes nowhere
    (close x) contents))                 ; <-- CONTENTS has never been changed

DO просто выполнит что-то для побочных эффектов.

COLLECT соберет результат и LOOP вернет список собранных значений при выходе.

Как уже упоминалось, используйте WITH-OPEN-FILE вместо OPEN / CLOSE.WITH-OPEN-FILE закроет файл после выхода из динамической области.Не только с обычного выхода, но и при возникновении ошибок при использовании UNWIND-PROTECT.

Если вы хотите прочитать содержимое файла, вы можете использовать READ-SEQUENCE.С обычными проблемами.Например, когда вы читаете файл ASCII как текст в строку, строка может быть короче файла.Например, Common Lisp будет внутренне представлять CRLF одним символом на платформах, где CRLF - это новая строка.Другой пример: в реализациях, поддерживающих Unicode, код UTF-8 в файле можно заменить одним символом.

8 голосов
/ 10 января 2018

Я добавлю библиотеки.

Редактировать еще проще, с uiop, который включен в ASDF:

(uiop:read-file-lines "file.txt")

https://github.com/fare/asdf/blob/master/uiop/stream.lisp#L445

также имеет

(uiop:read-file-string "file")

С Александрийский read-file-into-string и последовательность split:

(alexandria:read-file-into-string "file.txt")
(split-sequence:split-sequence #\Newline *)

С str :

(str:lines (str:from-file "file.txt"))
...