Наконец, по iostatus()-функции предоставляется возможность получать информацию по состояниям всех открытых в текущем сеансе файлов. При этом, учитываются как явно открытые по функциям {fopen, open, pipe}, так и неявно другими функциями доступа к файлам (например, readline-функцией). Функция возвращает результат своего вызова в виде списочной структуры, содержащей по меньшей мере три элемента, первые из которых соответственно определяют:
iostatus()[1] – общее число открытых функциями доступа файлов в текущем сеансе; iostatus()[2] – общее число текущих активных вложенных операций чтения файлов; iostatus()[3] – верхнее значение для iostatus()[1]+iostatus()[2], т.е. максимально допус- тимое число одновременно открываемых в текущем сеансе внешних файлов.
Тогда как, начиная с четвертого (если имеются открытые файлы), элементы возвращаемого iostatus-функцией списка представляют собой списки (в количестве, соответствующем числу открытых в текущий момент файлов). Каждый из 6-ти элементов такого списка, описывающего соответствующий открытый файл, соответственно определяет:
1 – номер логического канала в/в (определяется функциями доступа, открывшими файл);
2 – спецификатор файла (полный путь к файлу в системе каталогов Windows-среды);
3 – вид файла (STREAM, RAW, PIPE, PROCESS, DIRECT);
4 – FP = адрес указателя для STREAM-файла и FD = номер для файлов другого вида;
5 – текущий режим доступа к файлу (READ, WRITE); 6 – тип файла (TEXT, BINARY).
При этом, второй элемент списка-описателя файла представляет непосредственный идентификатор файла, если файл относится к {STREAM|RAW}-виду либо идентификатор {default|terminal} для файлов DIRECT-вида. Четвертый элемент списка-описателя дает внутреннее значение либо для указателя данного файла (FP), или номера (FD) логического канала в/в. Данная информация представляет особый интерес при работе с файлами PIPE-вида, ибо значения номеров внутреннего логического канала и возвращаемого {fopen, open, popen}-функциями доступа в общем случае не совпадают. В случае отсутствия открытых файлов iostatus-функция возвращает [0, 0, 7]-значение.
Закрытие всех открытых в текущем сеансе файлов производится как по предложению/ функции {done|stop|quit}, так и по клавишам (Alt+F4) выхода из сеанса, а также и по restart-предложению, восстанавливающему состояние пакета на момент его начальной загрузки. Тогда как выборочное закрытие файлов производится по {fclose|close|pclose}функции для ранее открытых соответственно по {fopen|open|pipe,popen}-функции файлов. Все эти функции имеют единый формат кодирования следующего вида:
{fclose|close|pclose}(<СФ1>, <СФ2>, ..., <СФn>)
где в качестве единственного аргумента выступает последовательность спецификаторов закрываемых файлов и/или логических каналов в/в. При этом, успешное завершение каждой из этих функций доступа закрывает соответствующие файлы и возвращает значение NULL. Явное закрытие файлов по рассмотренным функциям доступа не только обеспечивает реальную запись информации в файлы, но и освобождает занимаемые ими логические каналы в/в для других файлов, что в свете вышесказанного в целом ряде случаев представляется достаточно актуальным. Вообще говоря, все три функции закрытия файлов эквивалентны и взаимозаменяемы. Попытка закрыть несуществующий файл либо незадействованный логический канал в/в вызывает ошибочную ситуацию для Maple 6/7, тогда как для Maple 8-10 возвращается NULL-значение, как и в случае существующих закрытых файлов во всех релизах. Это одна из досадных недоработок, способствующая несовместимости релизов. При этом, попытка закрыть файл {default|terminal}-вида вызывает ошибочную ситуацию. После закрытия логического канала в/в его номер вновь используется в текущем сеансе. Во избежание возникновения особых ситуаций рекомендуется производить закрытие файлов только после завершения работы с ними. Наконец, следующие две функции доступа позволяют соответственно определять режим обязательной записи информации в файл и удалять как закрытые, так и открытые файлы из системы каталогов DОS. Прежде всего, по fflush(<СФ1>, ..., <СФn>)- функции обеспечивается режим обязательной записи в файл при выполнении каждой такой операции. Это распространяется как на открываемые неявно файлы, так и на открываемые явно по {fopen|popen}-функции. При этом, данная процедура производится автоматически при явном закрытии файла. Вызов fflush-функции ничего не возвращает. Использование fflush-функции представляется целесообразным, например, при таком режиме работы с данными, когда в течение сеанса с пакетом производится длительное формирование результатов вычислений с их периодическим сохранением в файле в режиме дописывания (APPEND-режим), что позволяет существенно повышать надежность сохранности полученных результатов, перед реальной записью в файл накапливающихся в пакетном буфере обмена данных.
По функции fremove(<СФ1>, ..., <СФn>) производится удаление из файловой системы DOS указанных своими спецификаторами и/или номерами логических каналов в/в файлов. В случае применения fremove-функции к открытому файлу он предварительно закрывается, а затем удаляется. Данная функция часто используется для обеспечения пустоты файла, в который должна производиться запись информации. Это не является излишним, ибо, например, по writeline-функции производится запись информации поверх уже существующей в файле в его начало, не изменяя остального содержимого. Это может привести к ситуации, когда начало файла содержит новую информацию, а его конец - старую, т.е. не производится полного обновления содержимого файла. Применение fremove-функции к отсутствующему файлу инициирует ошибочную ситуацию, которую можно обрабатывать программно. Успешное завершение вызова функции fremove возвращает NULL-значение. В следующем фрагменте иллюстрируется применение всех рассмотренных функциональных средств, образующих оболочку средств доступа к внешним файлам: открытие и закрытие файлов, тестирование состояния открытых файлов, а также удаление файлов из системы каталогов операционной среды ЭВМ:
> LK:= fopen(`C:/ARM_Book/Academy/Kristo`, WRITE, TEXT); ⇒ LK := 0 > writeline(LK, `Russian`, `Academy of`, `Natural`, `Sciences`,` - 30.12.2006`); ⇒ 50 > fclose(LK): LK:= fopen(`C:/ARM_Book/Academy/Kristo`, READ): M:= NULL: while LK <> P do P:= readline(LK): M:= M, P end do: M:= M[k]$k=1..nops([M]) - 1; M := "Russian", "Academy of", "Natural", "Sciences", " - 30.12.2006" > restart: readline("C:/ARM_Book/Academy/Kristo"); ⇒ "Russian" > restart; Ln:= open("C:\ARM_Book/Academy\RANS.agn", WRITE): writeline(Ln, `Salcombe`, `Eesti`, `Ltd.`, `is terminated in`, `December 1999`); ⇒ 51 > close(Ln): open("C:\ARM_Book/Academy\RANS.agn",READ): N:= NULL: while Ln <> P do P:= readline(Ln): N:= N, P end do: N:=N[k]$k=1..nops([N]) - 1; N := "Salcombe", "Eesti", "Ltd.", "is terminated in", "December 1999" > K:= "C:/ARM_Book/Academy/": [readline(cat(K, Kristo)), readline(cat(K, `RANS.agn`))]; ["Russian", "Salcombe"] > iostatus(); [3, 0, 7, [0, "C:\ARM_Book/Academy\RANS.agn", RAW, FD = 11, READ, BINARY], [1, "C:/ARM_Book/Academy/Kristo", STREAM, FP = 2009464032, READ, TEXT], [2, "C:/ARM_Book/Academy/RANS.agn", STREAM, FP = 2009464064, READ, TEXT]] > Ofiles:= () -> `if`(iostatus() = [0, 0, 7], true, false): Ofiles(); ⇒ false > CF:= cat(K, "RANS.agn"): fflush(CF): writeline(CF,"December 30th 2006"); ⇒ 19 > fclose(CF); fremove(CF, cat(K, `Kristo`)); ⇒ NULL > map(writeline, [CF, cat(K, `RAC. REA`)], "Tallinn",`Moscow`,Grodno,`Vilnius`,Gomel): > close(NULL): All_Close(); ⇒ NULL |
С учетом сказанного особых вопросов фрагмент вызывать не должен. Следует обратить внимание на процедуру All_Close(), вызов которой закрывает все открытые файлы.
All_Close := proc() local a k, ; assign(a = iostatus( )), close `if`( (a = [0 0 7, , ], RETURN(NULL), seq( `if`(member(a k[ ][2], {'terminal', 'default'}), NULL, a k[ ][2]), k = 4 .. nops(a)))) end proc |
Использованные выше для иллюстрации еще не рассмотренные процедуры writeline и readline следует пока рассматривать как некоторые формальные операции записи и чтения данных. Детализация их представляется несколько ниже.
При работе с файлами весьма существенную ее компоненту составляет обработка особой ситуации «конец файла», особенно актуальная в условиях использования функциональных средств доступа, поддерживаемых ядром Maple. Для этих целей Maple-язык предлагает тестирующую feof(<СФ>)-функцию, возвращающую true-значение только тогда, когда в процессе применения функций доступа readline, fscanf или readbytes к файлу STREAM-вида, определенному фактическим аргументом (спецификатор либо номер логического канала) функции, была реально обнаружена ситуация «конец файла», в противном случае возвращается false-значение. При этом, если в качестве фактического аргумента feof-функции был указан спецификатор и файл ранее не открывался, то он открывается в READ-режиме доступа как BINARY-файл.
По функции filepos(<СФ> {, p}) возвращается номер текущей сканируемой позиции файла, указанного первым фактическим аргументом (спецификатор или номер приписанного ему логического канала). Под сканируемой понимается такая позиция файла, в которую установлен указатель, т.е. в которую будет писаться либо из которой будет читаться логическая запись при очередной операции доступа к файлу. При этом, под логической записью понимается порция информации, записываемая/читаемая в(из) файл(а) за одну операцию обмена. Так, для {writeline|readline}-функции логической записью является строка, а для {writebytes|readbytes}-функции – заданное число байтов (символов). Если же указан второй необязательный аргумент функции, определяющий номер позиции в файле, то производится установка указателя в эту позицию с возвратом ее номера. В качестве номера позиции допускаются целочисленные положительные значения из диапазона [1 .. infinity]; нулевое значение filepos-функция возвращает для пустого файла и по достижении конца файла. Тогда как по вызову функции filepos(<СФ>, infinity) производится установка указателя в конец файла с возвратом количества байтов, составляющих файл, указанный ее первым фактическим аргументом. При этом, вызов filepos(<СФ>) эквивалентен вызову feof(<СФ>). С учетом сказанного и представленных в книгах [12,41] замечаний, feof-функция не может служить для надежного тестирования особой ситуации «конец файла» и для этих целей в режиме READ-доступа к TEXT-файлам следует использовать непосредственно readline-функцию или filepos-функцию. Например, по конструкции следующего простого вида: R:= readline(<СФ>): R:= `if`(R = 0, NULL, R) R-переменная получает фактические значения записей файла, указанного СФ-аргументом, либо NULL-значение по достижении конца файла. Следующий фрагмент иллюстрирует использование filepos-функции и некоторые варианты обработки ситуации «конец файла», которые наряду с ранее представленными могут оказаться весьма полезными: