## ЛЕКЦИЯ 10.

Чтение и запись информации в файлы

Содержание

  10.1 Задание параметров при определении функций.
  10.1.1 Необязательные параметры &optional
  10.1.2 Переменное количество аргументов &rest
  10.1.3 Ключевые параметры
  10.2 Входные и выходные потоки.
  10.3 Определение выходных и входных потоков.
  10.4 Чтение символов из файла

## 10.1 Задание параметров при определении функций.

При определении функции можно использовать механизм ключевых слов для того чтобы при вызове функций аргументы трактовать по разному.

С помощью ключевых слов в лямбда-списке можно выделить

- необязательные аргументы (optional)
- параметр, связываемый с хвостом списка аргументов изменяющейся длины (rest)
- ключевые параметры (key)

Ключевые слова начинаются с символа & и их записывают перед соответствующими параметрами в лямбда-списке.
Действие ключевого слова распростроняется до следующего ключевого слова.
Параметры, перечисленные в лямбда-списке до первого ключевого слова, являются обязательными.

## 10.1.1 Необязательные параметры &optional

Вы можете определить необязательные аргументы для вашей функции. Любой аргумент после символа &optional необязательный:

    * ( Defun bar ( x &optional y) ( if y x 0 ))
    bar
    * ( Defun baaz ( &optional ( x 3 ) ( z 10 )) ( + x z) )
    BAAZ
    * ( bar 5 )
    0
    * ( bar 5 t)
    5
    * ( Baaz 5 )
    15
    * ( Baaz 5 6 )
    11
    * (Baaz)
    13

Можно вызывать функцию bar или с одним или с двумя аргументами. Если она вызвана с одним аргументом, x будет связано со значением этого аргумента и незаданный аргумент y будет связан с nil; если она вызвана с двумя аргументами,x и y будут свя- заны со значениями первого и второго аргумента, соответственно.
Функция baaz имеет два необязательных аргумента. Кроме этого она определяет недостающие знaчения для каждого из них: если пользователь определит только один аргумент, z будет связано с 10 вместо nil, и если пользователь не определит никаких аргументов, x будет связана с 3 и z с 10.
Такое определение значений называется определение по умолчанию.

## 10.1.2 Переменное количество аргументов &rest

Вы можете задавать вашу функцию принимающей любое число аргументов, заканчивая список аргументов &rest параметром.
LISP будет собирать все аргументы не попавшие в обязательные параметры в список и связывать &rest параметр с этем списком.
Итак:

    * ( Defun foo ( x &rest y) y)

    FOO

    * ( Foo 3 )

    NIL

    * ( Foo 4 5 6 )

    (5 6)

    * ( defun fn ( x &optional y &rest z))
         (list x y z))
    fn

    * (fn 'a)

    (A NIL NIL)

    * ( a b (c d))

## 10.1.3 Ключевые параметры

Можно задать функции другой вид необязательного аргумента называемого аргументом ключевого слова. Пользователь может задавать эти аргументы в последующем в любом порядке, потому что они маркированы ключевыми словами.

Символы t и nil называются константами-символами, потому-что они при выполнении дают сами себя.

Существует целый класс таких символов, которые называются ключевыми словами; любой символ, чье имя начинается с двоеточия является ключевым словом.
(Ниже приведены некоторые использования ключевых слов).
Примеры:

    * :this-is-a-keyword

    :THIS-IS-A-KEYWORD

    * :so-is-this
    :SO-IS-THIS

    * :me-too
    :ME-TOO

     ( Defun foo ( &key x y) ( cons x y) )

    FOO

    * ( Foo :x 5 :y 3 )

    (5 . 3)

    * ( Foo :y 3 :x 5 )

    (5 . 3)

    * ( Foo :y 3 )

    ( NIL. 3 )

    * (Foo)

    (NIL)

    &key параметр может иметь также значение по умолчанию:

    * ( Defun foo ( &key ( x 5 )) x )

    FOO

    * ( Foo :x 7 )

    7

    * (Foo)

    5

    (defun test ( x &optional (y 3) (z 4) &rest  a)
    (cons z ( list x a y)))

    (test 1 2 3)

    (test 1)

    (test 3 4 5)

    (test 3 2 1 1 2 3)

## 10.2 Входные и выходные потоки.

При вводе и выводе информации в Лиспе используется понятие потоков - stream
Для потока определены ИМЯ , операции открытия open операции закрытия clouse направления output и input

## 10.3 Определение выходных и входных потоков.

Для открытия файла для записи задается его имя, производится операция open и указывается направление output:
(setq our-output-stream (open "sesame" :direction :output))
Зададим

(setq s 'e)

Можно вывести это значение в файл

(princ s our-output-stream) ;

Можно занести список

(print '(a b c d) our-output-stream)

Чтобы правильно закрыть поток необходимо в конец поместить

(terpri our-output-stream)

Затем файл закрывается

(close our-output-stream)

Можно посмотреть информацию в файле.
Откроем файл для чтения:

(setq our-input-stream (open "sesame" :direction :input))

Прочитае информацию

(read our-input-stream)

Закроем файл

(close our-input-stream)

## 10.4 Чтение символов из файла

Предположим, что в файле хранится символьная информация, необходимая нам для обработки. Причем нас интересует каждый символ в файле. До сих пор мы могли вводить только атомы, числа и списки.
Сформируем файл
Пусть

(setq s "---+++")
(setq p "+++---")

Определим поток вывода

    (setq our-output-stream (open "picture.spl" :direction :output))
    (princ s our-output-stream) ; записываем первую стороку
    (terpri our-output-stream) ;  заканчиваем ее
    (princ p our-output-stream) ; записываем вторую строку
    (terpri our-output-stream) ;  заканчиваем файл

Тепрь файл закрывается

(close our-output-stream)

В файле теперь находится

               ---+++
               +++---

Для чтения символов из файла будем использовать функцию

(READ-CHAR <входной поток>)

Данная функция позволяет читать печатные символы ( CHAR) из файла. В качестве значения получается десятичное представление кода символа.
Используе эту функцию для посимвольного ввода информации из файла для ее последующего анализа
Определим

(setq our-input-stream (open "picture.spl" :direction :input))

Для чтения символа используем

(read-char our-input-stream)

Будем получать последовательность значений

    43
    43
    43
    45
    45
    45
    10 и т.д.

Для восстановления содежимого файла применяется перекодировка

(setq x (read-char our-input-stream)

То содержимое x можно показать

     (cond (( = x 43) (prin1'+))
           (( = x 45) (prin1 '-))
           (( = x 10 ) (terpri)))

Можно представить информацию без искажений, если использовать цикл

    (loop (progn   (setq x  (read-char our-input-stream) )
              (cond (( = x 43) (prin1'+))
                   (( = x 45) (prin1 '-))
                    (( = x 10 ) (terpri))))))

После вывода имеем

               ---+++
               +++---

Закрытие входного потока

(close our-input-stream)

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

Содержание