Введение в Автолисп

Рыжиков Роман Клавдиевич

7. ОПЕРАЦИИ С ВНЕШНИМИ ФАЙЛАМИ

 

 

7.1. Вызов файла

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

(open имя_файла режим ) . Функция открывает файл в качестве объекта для осуществления операций ввода/вывода. Используется совместно с функцией (setq ...), присваивающей файлу некоторый идентификатор (дескриптор). Пример такой операции приводился ранее:

(setq bolt (open "mycalc.res” “г”)).

Имя_файла - это строковая константа, определяющая местоположение файла на носителе. Аргумент режим устанавливает условия взаимодействия с файлом. Используются следующие три режима:

“r” - файл открывается для чтения (read mode); если названный файл не существует, возвращается nil;

“w” - файл открывается для записи (write mode); если названный файл не существует, создается и открывается новый, если же он существует, содержащиеся в нем данные уничтожаются в процессе записи;

“а” - файл открывается для продолжения работы с ним (append mode); если файл не существует, он создается и открывается подобно предыдущему случаю, если существует, то указатель устанавливается в конце файла, и новые данные присоединяются к уже существующим.

(load имя_файла [сообщение] ) . Функция загружает файл в выражение Автолиспа и обрабатывает это выражение.

Аргумент имя_файла указывается без расширения (расширение .lsp подразумевается по умолчанию) и может содержать полный путь к файлу. Следует помнить, что если в константе имя_файла встречается обратная косая черта, она должна повторяться дважды (см. табл. 2):

(load “\\support\\my_func”).

Если путь к файлу не указан, Автолисп просматривает доступные директории в следующем порядке: текущая директория, директория текущего рисунка, директории, указанные в переменных окружения, директория, в которой расположены программные файлы Автокада.

Если операция прошла успешно, функция возвращает значение последнего выражения в файле. Если по каким-либо причинам операция невыполнима. Автолисп возвращает сообщение об ошибке и прекращает операцию. Однако включение аргумента сообщение вынуждает Автолисп вернуть его значение и позволяет совершить альтернативную операцию. Следует только помнить, что текст сообщения должен отличаться от последнего выражения в файле.

(close дескриптор_файла ) . Функция закрывает файл и возвращает nil. Аргумент дескриптор_файла должен соответствовать таковому в функции open. После закрытия дескриптор файла не изменяется, но он имеет силу только при открытии файла.

(findfile имя_файла ) . Функция отыскивает файл в доступных директориях и, если находит, возвращает его дескриптор, в противном случае возвращает nil.

 

7.2. Функции преобразования

Функции преобразования играют существенную роль при чтении файлов. Их основная задача - преобразование строковых констант в числовые и наоборот.

(ascii строка ) . Функция преобразует первый символ строки в целочисленную константу, соответствующую коду ASCII для этого символа.

(ascii "А”) возвращает 65,

(ascii “BIG”) возвращает 66,

(ascii “а”) возвращает 97.

(atof строка ) преобразует строку в вещественное число.

(atof “67.5”) возвращает 67.5,

(atof “45”) возвращает 45.0.

(atoi строка ) преобразует строку в целое число.

(atoi “45”) возвращает 45,

(atoi “67.5”) возвращает 67.

(chr целое_число ) преобразует целое число в соответствующий символ таблицы ASCII, представляя его как строку.

(chr 65) возвращает “А”,

(chr 66) возвращает “В”,

(chr 97) возвращает “а”.

(itoa целое_число ) преобразует целое число в соответствующую ему строку.

(itoa 65) возвращает “65”,

(itoa -20) возвращает “-20”.

 

7.3. Извлечение данных из файла

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

(read строка ) . Функция возвращает первый атом или список, принадлежащий строке, сохраняя при этом тип переменной.

(read “hello”) возвращает атом HELLO,

(read “hello there”) возвращает строку HELLO,

(read “(a b с) d”) возвращает список (А В С),

(read “1.2300”) возвращает вещественное 1.23,

(read “87 3.2”) возвращает целое 87.

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

(read-char [дескриптор_файла] ) . Функция считывает первый символ из строки, введенной с клавиатуры, или из открытого файла, определенного дескриптором, и возвращает код ASCII этого символа. При повторном обращении к функции считывается следующий символ и так далее. Если дескриптор файла не указан, общение осуществляется с командной строкой.

Пусть буфер командной строки пуст. На вызов (read-char) Автолисп не реагирует, ожидая действий оператора. Ввод в командную строку последовательности ABC Enter возвращает 65 (десятичный ASCII-код символа А). Последующие три вызова функции возвращают последовательно 66, 67, 10 (код перевода строки). Следующий вызов функции устанавливает компьютер в режим ожидания. Важно помнить, что функция Автолиспа не является командой Автокада, поэтому ее нельзя вызвать повторно клавишей Enter или правой клавишей мыши, она всегда должна вводиться явно.

(read-line [дескриптор_файла] ) . Функция считывает строку с клавиатуры или из файла. Ее действие аналогично предыдущему: каждый последующий вызов приводит к чтению очередной строки, что позволяет просмотреть весь файл.

(strcat строка1 [строка2] ... ) . Функция возвращает строку, представляющую собой сцепление строк строка1 , строка2 и т.д.

Примеры:

(strcat “Auto” “CAD”) возвращает “AutoCAD”,

(strcat “fi” “le”) возвращает “file”.

(strlen [строка] ) возвращает целое число, соответствующее числу символов в строке.

(strlen "file”) возвращает 4,

(strlen "file” “desk” “top”) возвращает 11,

(strlen) возвращает 0.

(substr строка начало [длина] ) . Функция возвращает подстроку строки , начинающуюся с позиции начало и захватывающую количество символов, соответствующее длине . Аргументы начало и длина должны быть целыми числами.

(substr “abcde” 2) возвращает “bcde”,

(substr “abcde” 2 1) возвращает “b”,

(substr “abcde” 3 2) возвращает “cd”.

Две функции - (write-char число [дескриптор_файла]) и (write-line строка [дескриптор файла ]) - в примерах не нуждаются. Их задача - записывать в файл символы или строки.

 

7.4. Пример обработки файла

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

¬¬1¬¬¬¬0¬¬¬¬¬0.0000¬¬¬¬¬¬¬0.0000

¬¬2¬¬¬¬5¬¬¬¬¬6.4214¬¬¬¬¬¬¬8.2349

¬¬З¬¬¬10¬¬¬¬¬8.7965¬¬¬¬¬¬26.1500

и так далее. В четырех столбцах файла расположены следующие параметры: порядковый номер строки, значение аргумента (например, указан шаг счета нарастающим итогом), координаты X и Y расчетных точек, символом  ¬ обозначены обусловленные форматом вывода незаполненные позиции в строках данных.

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

Длина строки файла составляет 32 позиции. В соответствии с оговоренным условием значения координат могут занимать 9 позиций. Для перестраховки установим длину читаемых позиций, равной 10 символам (вдруг в файле неожиданно для нас окажется число с четырехзначной целой частью).

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

Итак, напишем функцию, извлекающую из чертежа координаты точек.

1 (defun pnt ()

2 (setq lin (read-line file1))

3 (setq x1 (atof (substr lin 10 10)))

4 (setq y1 (atof (substr lin 23 10)))

5 (setq pt1 (listx1 y1))

)

Строка 1 устанавливает имя программируемой функции pnt, строка 2 считывает из файла, определенного дескриптором file1, первую строку lin, рассматривая ее как строковую переменную. Далее (строка 3) функция substr считывает информацию, содержащуюся в позициях 10...19 строки lin, функция atof преобразует считанную строковую переменную в числовую, а уже setq приписывает это значение координате x1. Аналогичные действия выполняет строка 4, устанавливая координату y1. Наконец, выделенные координаты приписываются точке pt1 (строка 5).

Если остановиться на вычерчивании за один прием участка полилинии, проходящего через две точки, то соответствующая функция будет выглядеть, например, следующим образом:

(defun otr ()

    (command “pline” pt1 “w” “0” “” pt2 “”)

).

Теперь можно написать полностью программу, обрабатывающую файл результатов расчета любой длины.

;;; ==============================================

(defun cdraw ()

;;; ==============================================

;;; подавление вывода текста на экран

    (setq svar_old (getvar “cmdecho”))

    (setvar “cmdecho” 0)

;;; загрузка штрих-пунктирной линии

    (if (tblsearch "ltype" "Acad_ISO04w100")

      (princ)

    (command "linetype" "load"

      "Acad_ISO04w100" "acadiso.lin" "" "")

    )

;;; сохранение текущего слоя

    (setq lay_old (getvar "clayer"))

;;; создание нового слоя в чертеже

    (command "layer" "new" "cam"

      "c" "magenta" "cam"

      "I" "Acad_ISO04w100" "cam"

      "s" "cam" "")

;;; вызов файла и чтение первой строки

    (setq get_F (getstring "Введите имя файла:"))

    (setq file1 (open (strcat get_F) "r"))

    (setq t1 (pnt))

;;; организация цикла счета строк файла

        (setq k 0)

    (while (read-line file1)

    (setq k (+ k 1))

    )

        (close file1)

;;; чтение файла и обрисовка профиля

        (setq file1 (open get_F “г”))

    (repeat (- k 1)

        (setq t2 (pnt))

        (otr)

        (setq t1 t2)

    )

    (close file1)

  (command “layer” “s” lay_old)

  (setvar “cmdecho” svar_old)

  (princ)

)

Разумеется, в текст программы должны быть включены функции, описанные в этом параграфе (имеются в виду функции pnt и otr).

Приведенный пример представляет собой фрагмент программы, используемой для автоматической обрисовки центрового профиля кулачка. Дополнительно реальная программа выполняет операции объединения сегментов полилинии, генерирования типа линии, размещения изображения профиля в нужном месте чертежа и поворота изображения на заданный угол. To обстоятельство, что профиль очерчивается отрезками прямых, не играет существенной роли, так как при малом шаге счета (он в реальной программе принят равным одному угловому градусу, а может быть установлен сколь угодно малым) визуально профиль не отличается от такового, построенного с помощью сплайна.

И последнее замечание. Приведенный фрагмент содержит два цикла: while и repeat. Это сделано лишь для иллюстрации принципов их построения. В реальной программе достаточно одного цикла while.