Как я могу прочитать содержимое файла в списке в Lisp?

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

(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))

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

Ответ 1

Как насчет

(defun get-file (filename)
  (with-open-file (stream filename)
    (loop for line = (read-line stream nil)
          while line
          collect line)))

Ответ 2

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

(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

LOOP

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

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

Открытие и закрытие файлов

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

Чтение содержимого файла

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

Ответ 3

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

редактировать еще проще, с помощью 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 и разделенной последовательностью:

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

С ул.:

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