Pull to refresh

Работа с файлами в Dyalog APL

Reading time 5 min
Views 1.8K
Всем привет. Сегодня я расскажу (и покажу) вам, как организована работа с файлами в Dyalog APL. Экспериментировать будем с «родной» файловой системой Dyalog – DCF, остальные файлы в данной статье не рассматриваются. Также будет затронута тема обработки исключений. Все опыты будут проводится на материале из прошлого топика. К сожалению, некоторые изображения хренового качества, прошу меня извинить, ибо не знаю хорошего хостинга картинок. Итак, поехали.


Что такое DCF?


В Dyalog APL существует свой способ хранения информации – компонентные файлы. Суть такова:
файл – это последовательность «ячеек» (компонент), причем в каждую из них можно записать значение только одной переменной. Над файлом можно проводить следующие операции: создать, открыть, считать компоненту, заменить компоненту, присоединить новую компоненту в конец, закрыть и различные специальные операции, в данной статье не рассматриваемые.
Попробуем открыть какой-нибудь файл:

image

И получаем ошибку, ведь файла то нет. Из этого «эксперимента» можно сделать 2 вывода:
— для открытия файла используется системная функция []FTIE. Её аргументами являются полное имя файла слева и специальный номер-идентификатор файла (tie number), который в дальнейшем используется для обращения к файлу;
— сообщения об ошибках выдаются в окно интерпретатора с указанием причины ошибки (в нашем случае это FILE NAME ERROR). Немного забегая вперед отмечу, что у каждой ошибки есть свой номер, что используется для перехвата этих самых ошибок.
Итак, открыть файл не получилось. Значит надо его создать! Для этого используется системная функция []FCREATE с такими же аргументами, что и []FTIE.

image

Ну вот, теперь у нас есть файл test.dcf с идентификационным номером 1. По умолчанию (если не указать полный путь) файлы появляются на рабочем столе. Созданные файлы не содержат компонент, в чем можно убедиться при помощи системной функции []FSIZE, передав ей номер файла справа.

image

Нас пока интересует только второй элемент результата этой функции – он содержит номер следующей свободной компоненты. Так как для файла test.dcf этот номер равен 1, то число компонент равно нулю.
Для заполнения файлов используется системная функция []FAPPEND, которой необходимо передать переменную или значение слева и номер файла справа. Чтобы проверить, что информация действительно записалась, воспользуемся функцией []FREAD. Она принимает один аргумент из двух значений – номера файла и номера компоненты.

image

Для закрытия файла используется функция []FUNTIE с номером файла. Чтобы убедиться, что связи с файлом больше нет, воспользуемся nyladic функцией []FNUMS, которая возвращает вектор номеров файлов.

image

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

Немного практики


Внесем в программу несколько изменений:
1. Запишем в файл, использующийся в программе текст и будем загружать его при выполнении.
2. Запишем в другой файл тексты функций и будем выполнять их при загрузке рабочей области, а при выходе – сохранять обратно в файл.

Сохранение и загрузка текста

Сначала напишем функцию, которая будет осуществлять инициализацию текста программы – txtIni. Нам необходимо: открыть файл, если файла не существует то создать его и записать текст, считать текст в глобальную (для данной функции) переменную и закрыть файл.
Заголовок функции будет выглядеть так:

image

Функция принимает полное имя файла в качестве аргумента (fname). Переменная tien будет хранить номер файла.
При работе с файлами легко допустить ошибку, поэтому необходимо воспользоваться инструментами обработки ошибок. Для нашего примера подойдет конструкция :Trap :Else :EndTrap, которая несколько похожа по идеологии на try-catch.

image

Конструкция :Trap 0 1000 определяет коды ошибок, которые должны перехватываться. В данном случае это все системные события (0) и все пользовательские (1000). Также внутри этих границ можно определить обработку отдельных событий при помощи конструкций :Case и :CaseList. Обратите внимание на применение метки L1: — она используется для безусловного перехода после обработки исключения. Остальное просто: если файл содержит компоненты, читаем первую в переменную txt, если нет – заполняем её текстом и пишем в файл. Затем файл закрываем.
Далее необходимо определить последовательность действий при возникновении ошибок. Для отсутствия файля пишем отдельный :Case, для остальных — :Else. Самое простое, что можно сделать при непредвиденных ошибках – это закрыть все открытые файлы функцией []FUNTIE с аргументом []FNUMS, а затем выдать сообщение в окне интерпретатора при помощи функции []SIGNAL. Её аргументами являются текст сообщения справа и код ошибки слева. В нашем примере достаточно будет воспользоваться системными переменными []DM(текст) и []EN(код возникшей ошибки). При отсутствии файла (или неверно указаном имени) этот файл создается и затем осуществляется переход на метку. Всё очень просто!

image8

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

image9

В функции WhatNum был убран аргумент, так как его значение(заголовок формы) теперь берется из файла. Все символьные константы были заменены на обращение к элементам вектора txt с вызовом функции «Disclose», которая преобразует вложенный элемент вектора в символьный вектор. В функции checkNum изменения те же:

image10

Прячем код

А теперь самое интересное: в компонентных файлах можно хранить переменные, но можно ли хранить функции? ДА! Для этого нужно только преобразовать функцию в текст и присвоить его переменной, что и будет делать функция saveFns.
Преобразование делается моментально: системная функция []CR (canonical representation) с именем функции в качестве аргумента возвращает символьную матрицу с текстом. Но настоящая магия начинается с применением оператора «Each».

image11

Таким образом, переменная all содержит три текста наших функций причем каждый текст представляет собой символьную матрицу, представленную в виде скаляра(ранг равен 0)!
Далее следует уже описанная процедура записи в файл. В конец добавим вызов системной функции []EX, которая удалит из рабочей области ненужные объекты.

image12

Теперь осталось написать код начальной инициализации, который и будет выполняться при загрузке рабочей области. Последовательность действий такая: открытие файла, чтение, закрытие файла. Далее опять начинает работать магия APL: легким движением руки вектор all превращается в полноценные функции рабочей области! После загрузки функций можно вызвать WhatNum и убедиться, что всё работает.

image13

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

image14

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

Итого


Cегодня вы увидели немного магии APL, а заодно узнали о таких важных вещах как работа с файлами и обработка исключений. Продолжение следует.
Tags:
Hubs:
0
Comments 2
Comments Comments 2

Articles