Для файлов DIRECT-вида дополнительно определяются два предопределенных типа: default и terminal. Подобно развитым программным средствам функции доступа Mapleязыка интерпретируют интерфейс с пользователем как файлы с именами двух типов: default и terminal. Первый из них определяет текущий входной поток, в рамках которого пакет читает и обрабатывает запросы пользователя. Тогда как второй файл определяет входной поток высшего уровня, который в начале загрузки пакета являлся текущим. Первый файл определяет ввод/вывод пакета по умолчанию; например, в интерактивном режиме под default-файлом понимается ввод/вывод с консоли (клавиатура+дисплей). Тогда как второй определяет высшего уровня ввод/вывод текущего сеанса работы с пакетом. В режиме интерактивного функционирования пакета оба типа пакетных файлов совпадают. Точнее, при отсутствии read-предложения terminal-ввод эквивалентен default-файлу, а при отсутствии процедур writeto или appendto terminal-вывод также эквивалентен default-файлу. Различия возникают лишь в случае чтения/записи предложений Mapleязыка посредством указанных функций. В случае Windows-платформы default-файл относится к потоку, из которого производится чтение, а файл terminal – к текущему сеансу работы с пакетом. Так как для Unix-платформы входной поток поступает из файла либо канала, то terminal-файл относится именно к ним.
В заключение напомним, что для идентификации в функциях доступа собственно самого файла используются два подхода: на основе его спецификатора (СФ), определяющего полный путь к нему и кодируемого в следующем виде:
`<УВВ>:{\|/}<Подкаталог_1>{\|/}...{\|/}<Подкаталог_k>{\|/}<Имя>.<Расширение>`
"<УВВ>:{\|/}<Подкаталог_1>{\|/}...{\|/}<Подкаталог_k>{\|/}<Имя>.<Расширение>" например: `C:\ARM_Book/Academy\Tallinn/RANS.IAN`, и номера логического канала в/в, детально рассматриваемого ниже. В принципе, оба способа указания файла эквивалентны, однако в отдельных случаях предпочтение отдается одному из них. В частности, предпочтение второму способу отдается при программировании задач доступа, характеризующихся частыми обращениями к файлу. Наряду с этим, второй подход делает программы более гибкими к возможным модификациям. С ростом опыта программирования задач доступа в среде Maple пользователь практически начинает ощущать всю целесообразность использования того или иного способа в каждом конкретном случае. Большинство функций доступа Maple-языка допускает использование как первого, так и второго способа идентификации файлов.
Между тем, Maple-язык не отождествляет СФ, закодированные хоть и одинаковыми, но на различных регистрах буквами либо символами разделителей каталогов {«/», «\»}. В этой связи появляется возможность открывать один и тот же файл на разных каналах и в различных режимах доступа. Так, наша процедура open2 обеспечивает открытие файла сразу на двух логических каналах в/в в различных режимах доступа [41,103,108,109].
Вызов процедуры open2(F, L, P, N) обеспечивает открытие файла со СФ F на двух логических каналах в/в, номера которых возвращаются через аргументы L, P, а через N размер файла в байтах соответственно. Файл F открывается посредством функции open на логическом канале L и посредством функции fopen на логическом канале P. Успешный вызов процедуры open2(F, L, P, N) возвращает NULL-значение, т.е. ничего. Дополнительно, вызов процедуры допускает до трех аргументов, определяющих режимы доступа на каналах L, P и тип файла по каналу P соответственно. Детальнее с процедурой можно ознакомиться в [41-43,103,108,109].
open2 := proc(F::{string, symbol}, L::evaln, P::evaln, N::evaln) local h n J, , ; `if`(type(F, 'file'), assign(h = CF(F)), ERROR "<%1> is not a file",( F)); assign(n = op convert(( substring(h, 1), 'bytes')), N = filepos(h, ∞)); `if`(65 ≤ n and n ≤ 90, assign(J = cat(convert([n + 32], 'bytes'), substring(h, 2 .. length(h)))), assign(J = cat(convert [( n − 32], 'bytes'), substring(h, 2 .. length(h))))); op([close(h), assign(L = open(h, `if`(4 < nargs args[5] ', , READ')), P = fopen(J, `if`(5 < nargs args[6] ', , READ'), `if`(nargs = 7, args[7] ', BINARY'))) ]) end proc > open2("C:/Tmp/Demo\Ans.rtf/", L, P, N, WRITE, APPEND, TEXT): iostatus(), L, P, N; [2, 0, 7, [0, "c:\tmp\demo\ans.rtf", RAW, FD = 11, WRITE, BINARY], [1, "C:\tmp\demo\ans.rtf", STREAM,FP = 2013506696, READ, TEXT]], 0, 1, 1 |
С другими нашими средствами, относящимися к открытию файлов данных, а также с рядом их особенностей, полезных для программирования, можно ознакомиться в [103].
В общем случае процедура доступа к файлу имеет вложенную структуру, в которой ядро, состоящее из функций собственно обработки файла (запись, чтение, дописывание и др.), обрамляется оболочкой, содержащей функции соответственно открытия и закрытия файла. При этом, следует иметь в виду, что процедура закрытия файлов в общем случае необязательна, ибо в результате завершения работы с пакетом (Exit, quit, done, stop) либо выполнения restart-предложения все открытые в текущем сеансе работы с ним файлы автоматически закрываются. Однако, во избежание потери информации (в ряде случаев из пакетного буфера обмена в файл могут быть переданы не все данные) рекомендуется производить явное закрытие всех открытых пользовательских файлов. Более того, ввиду возможности одновременно открывать относительно небольшое число файлов (не более 7) следует четко отслеживать режим своевременного закрытия не требующих доступа файлов, позволяя открывать для доступа другие файлы, не вызывая ошибочных ситуаций типа «… too many files already open». Для возможности расширения числа доступных логических каналов в/в можно использовать упомянутую выше процедуру holdof.
Для обеспечения доступа к буферированным (Б) и небуферированным (НБ) файлам Mapleязык располагает парами функций открытия/закрытия файлов соответственно:
(Б) fopen(<СФ>, {READ|WRITE|APPEND{, TEXT|, BINARY}}) fclose(<СФ>)
(НБ) open(<СФ>, {READ|WRITE}) close(<СФ1>, ..., <СФn>)
Следует отметить, что Maple-язык имеет соответствующее функциональное обеспечение для оболочки процедур доступа и к файлам видов PIPE и PROCESS (модульные функции popen и pclose из process-модуля пакета). Однако здесь данные средства не обсуждаются, ибо файлы PIPE-вида поддерживаются только для Unix-платформы, а PRОCESSвида только для платформ, обеспечивающих многопроцессовый режим функционирования (например, Unix-систем). Рассмотрим средства оболочки функций доступа несколько детальнее.
По fopen-функции производится открытие файла, заданного своим спецификатором
(первый фактический СФ-аргумент), для буферированного доступа, режим которого определяется вторым фактическим {READ|WRITE|APPEND}-аргументом. При этом, третий необязательный аргумент определяет {TEXT (по умолчанию)|BINARY}-тип создаваемого файла. При этом, следует иметь в виду, что корректные способы кодирования спецификатора приводятся в нижеследующем фрагменте, в иных же случаях возможны некорректные ситуации создания файлов. А именно, наиболее общее правило кодирования спецификатора состоит в соответствии его соглашениям среды MS DОS, но с одним лишь исключением: если в качестве разделителя подкаталогов используется обратный слэш, то он должен удваиваться. Результатом успешного открытия файла является возврат целого числа (0-6), определяющего номер логического канала в/в.
Логический канал в/в идентифицируется уникальным для всех открытых файлов текущего сеанса n-номером, значение которого будет находится в диапазоне 0-6; при этом, нумерация каналов производится безотносительно их имен. Для стандартных и специальных каналов пакет располагает рядом зарезервированных имен, например имена: default и terminal определяют соответственно ввод/вывод пакета по умолчанию и высшего уровня в/в текущего сеанса. В функциях доступа к открытому файлу можно впоследствии кодировать как непосредственно его спецификатор, так и номер приписанного ему логического канала в/в.
Вообще говоря, существующий файл не требует предварительного открытия по fopenфункции для обеспечения к нему доступа, т.к. первая же функция доступа к нему открывает файл. Однако fopen-функция имеет два весьма важных аспекта: (1) обеспечивает совместимость текстов программ, импортируемых из ряда популярных языков программирования, и (2) позволяет переопределять тип файла, присвоенный ему по умолчанию функциями доступа. При этом, если по fopen-функции открывается существующий файл с указанием для него TEXT-типа, то в нем выделяются управляющие hex(0D0A)символы в качестве разделителей строк, т.е. файл построчно структурируется, позволяя организовывать к нему доступ на уровне составляющих его строк. Такого типа файлы являются наиболее широко используемым типом внешних данных для многих хорошо известных ПС, позволяя легко поддерживать мобильность информации. В противном случае файл будет представлять однородную последовательность байтов. При открытии существующего файла в режиме WRITE-доступа он обновляется, тогда как по режиму APPEND производится дописывание информации в конец файла. Все возникающие особые и ошибочные ситуации при вызове fopen-функции вполне адекватно отражаются выводимой диагностикой, доступной для обработки описанными ниже средствами Maple-языка.
По open-функции производится открытие небуферированного файла, спецификатор которого определен первым фактическим СФ-аргументом, в заданном вторым фактическим {WRITE|READ}-аргументом режиме. В случае успешного завершения операции открытия функция возвращает выделенный файлу номер логического канала. При этом, на количество открываемых по open-функции файлов накладывается то же ограничение, что и для fopen-функции, а общее одновременно открытое в текущем сеансе число пользовательских файлов не должно превышать 7. Следует отметить, что для других платформ пакета данное число может быть большим. Файлы RAW-вида, открываемые по open-функции, обрабатываются как файлы BINARY-типа. В остальном сказанное относительно fopen-функции в значительной степени относится и к open-функции. Все возникающие особые и ошибочные ситуации при вызове open-функции вполне адекватно отражаются выводимой диагностикой, доступной для обработки рассмотренными ниже средствами Maple-языка.