Файловый ввод-вывод

Файловый ввод-вывод это одна из базовых возможностей любого языка программирования. Без неё программы как бы замкнуты сами в себе и не имею смысла. Раньше мы ограничивались выводом на экран. Теперь пора научиться писать и читать файлы.

Посимвольное чтение

Для того, чтобы открыть файловый поток используется функция open.

(open "/some/file/name.txt")

Эта функция открывает некоторый файл в посимвольном режим. Теперь мы можем читать из него с помощью функций read-line, read-char и read. А закрыть с помощью close.

(let ((in (open "/some/file/name.txt")))
      (format t "~a~%" (read-line in))
(close in))

У открытия файла есть несколько режимов. Ими управляет ключ :if-does-not-exists. Три различных значения допустимы для данного ключа:

  • :error — ошибка в случае отсутствия (по-умолчанию).
  • :create — создать файл, если не существует.
  • NIL- вернуть nil есть файла не существует.

Все функции чтения — READ-CHAR, READ-LINE, READ — принимают опциональный аргумент, по умолчанию «истина», который указывает должны ли они сигнализировать об ошибке, если они достигли конца файла. Исправим наш пример, сделав его более стабильным.

(let ((in (open "/some/file/name.txt" :if-does-not-exist nil)))
      (when in
            (loop for line = (read-line in nil)
            while line do (format t "~a~%" line))
      (close in)))

 

Двоичное чтение

Для того, чтобы открыть файл в двоичном режиме нужно передать функции open ключевой параметр :element-type со значением ‘(unsigned-byte 8). После чего мы можем читать побайтно с помощью функции read-byte.

Блочное чтение

Последняя функция для чтения, READ-SEQUENCE, работает с бинарными и символьными потоками. Она принимает последовательность, в которую нужно считать данные и ключевые аргументы :start и :end, которые указывают на подпоследовательность. Скорее всего данная функция эффективней чтения при помощи read-char или read-byte.

Файловый вывод

Для записи данных в файл необходим поток вывода, который можно получить вызовом функции OPEN с ключевым аргументом :direction :output. В случае если файл уже существует вернётся ошибка, но это поведение можно переопределить помощью ключевого аргумента :if-exists:

  • :supersede — заменяет текущий файл
  • :append — дозапись в конец файла
  • :overwrite — перезапись с начала. Старые данные сохранятся если мы не дойдём до них.
  • NIL — вернётся nil вместо потока.

Для записи в файл используются функции write-char, write-line. Если как и в случае чтения передать :element-type ‘(unsigned-byte 8), то можно записывать байты с помощью write-byte. И, наконец, симметричная функция для записи последовательностей так же существует это WRITE-SEQUENCE.

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

Файлы закрываются с помощью close. Важно закрыть открытые файлы, иначе это может привести к блокировке. Поскольку не всегда удаётся избежать ошибок при открытии, то существует макрос with-open-file, который берёт на себя заботы по закрытию файла.

(with-open-file (stream "/some/file/name.txt")
                (format t "~a~%" (read-line stream)))

(with-open-file (stream "/some/file/name.txt" :direction :output)
                (format stream "Какой-то текст."))

 

Пока на этом всё. Имён файлов коснёмся в следующий раз.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.