Смекни!
smekni.com

Программирование и разработка приложений в Maple (стр. 101 из 135)

> F:= "C:/temp/grsu": for k to 5 do writeline(F, "string"||k) end do: n:= filepos(F, infinity): close(F);

> h:= 1: s:= NULL: while h <> 0 do h:= readline(F); s:=s, h end do: close(F), s, iostatus();

"string1", "string2", "string3", "string4", "string5", 0, [0, 0, 7]

> h:= 1: s:= NULL: while filepos(F) <> n do s:= s, readline(F) end do: close(F), s, iostatus();

"string1 ", "string2 ", "string3 ", "string4 ", "string5 ", [0, 0, 7]

Первый пример фрагмента представляет создание простого TEXT-файла, содержащего 5 строк (записей), определяется его размер, затем файл закрывается. Во втором примере построчно считываются записи файла до получения readline-функцией нулевого значения, зпатем файл закрывается и производится проверка состояния логических каналов в/в. Наконец, третий пример подобен второму с тем отличием, что ситуация «конец файла» отслеживается проверкой на исчерпание всего файла. Здесь мы можем обнаружить в конце выводимых строк символ «&bsol;n», определяющий перевод строки и возврат каретки. Это обусловлено тем, что второй способ контроля использует количество считанной информации, а не ее построчную обработку. Поэтому в выходных данных и появляются управляющие символы. В представленных примерах для иллюстрации были использованы не рассмотренные функции writeline и readline, которые следует рассматривать пока как некоторые формальные операции записи и чтения данных соответственно.

Существенное различие между файлами типов TEXT и BINARY имеет место относительно обработки ситуации «the end of datafile» («конец файла»). Для BINARY-файлов у Maple нет средств для обработки этой особой ситуации и в каждом конкретном случае данная задача возлагается на пользователя, что во многих случаях нежелательно. Данный вопрос достаточно детально рассматривался в наших книгах [12,41,103]. С целью решения данной проблемы нами были предложены две процедуры Fend и Find.

Fend := proc(F::{integer, string, symbol}) local k a b c p h, , , , , ; assign(a = iostatus( )), seq `if`( (a k[ ][1] = F or a k[ ][2] = cat("", F), assign(' 'h = 9, ' 'c = a k[ ][1]), NULL), k = 4 .. nops(a)); if h ≠ 9 then error "<%1>: datafile is closed or datafile descriptor is not used", F end if; try assign(p = filepos( )c ); if filepos(c, ∞) ≤ p then return assign(b = filepos(c p, )), true else return false, `if`(nargs = 1, assign(b = filepos(c p, )), op( [assign([args][2] = [p, filepos(c, ∞) − p]), assign(b = filepos(c, p))])) end if

catch : null(

"Processing of an especial situation with datafiles {direct, process, pipe})"

end try

end proc

Find := F::{0, 1, 2, 3, 4, 5, 6} → [`if`(type(eval(cat(__filesize, F)), 'symbol'), ]

[assign(cat(__filesize F, ) = filepos(F, ∞)), filepos(F, 0)], NULL), -1

`if`(eval cat(( __filesize F, )) ≤ filepos(F), [true, unassign cat(( __filesize F, ))] , false)

1

> s:= NULL: p:= open(F, READ): while not Fend(p) do s:= s, readline(p) end do: close(F), s, iostatus(); ⇒ "string1 ", "string2 ", "string3 ", "string4 ", "string5 ", [0, 0, 7]

> s:= NULL: p:= open(F, READ): while not Find(p) do s:= s, readline(p) end do: close(F), s, iostatus(); ⇒ "string1 ", "string2 ", "string3 ", "string4 ", "string5 ", [0, 0, 7]

Вызов Fend(F {, 'h'}) возвращает true в случае обнаружения у файла F, заданного СФ или номером логического канала, ситуации «конец файла» и false в противном случае. Через второй необязательный аргумент в случае false-значения возвращается список формата [сканируемая позиция файла, длина остатка файла]. Процедура Fend имеет смысл только для открытого файла. В отличие от Fend, процедура Find имеет только один аргумент, определяющий номер логического канала, по которому открыт теституемый файл. Во фрагменте использован файл, полученный в предыдущем фрагменте.

6.2.3. Обработка особых и ошибочных ситуаций процедур доступа к файлам данных

В процессе выполнения процедур доступа к файлам данных возможны различного рода ошибочные и особые ситуации, наиболее часто встречающиеся из которых рассмотрены в наших книгах [12,32]. Обработку данных ситуаций можно производить, например, на основе функции traperror, переменных пакета lasterror и tracelast, функции ERROR и предложений error и try, из которых последнее является наиболее развитым средством обработки ошибочных ситуаций в целом. Нижеследующий фрагмент иллюстрирует использование try-предложения при реализации процедуры BootDrive, вызов BootDrive() которой возвращает 2-элементный список, чей первый элемент определяет логическое имя устройства начальной загрузки операционной системы, тогда как второй элемент определяет путь к главному системному каталогу. Предложение try рассмотрено выше.

BootDrive := proc()

local a b c v k t1 t2 f, , , , , , , , D, , ,x y w G, ;

D := (x y, ) → op {( seq(`if`(search(x k, ), RETURN( )k , false), k = y)}); G := proc(k w, ) local n h z, , ; z := cat(k, ":&bsol;Boot.ini"); n := fopen ,(z 'READ', 'TEXT'); while not Fend(n) do h := CF2 readline(( n)); if Search2(h, {"multi(" "signature(", }) ≠ [ ] and

search(h, cat(" ", w)) then RETURN(Close(z), map(Case, [k, cat(k, ":" FNS(, sextr(h, "&bsol;", ssign)[1], " " 3, ))], 'upper')) end if

end do;

Close( )z , ERROR "system file BOOT.INI is corrupted"( ) end proc ; assign(a = map(CF2, {Adrive( )}), t1 = {"95" "98" "me", , }, t2 = {"2003" "2000" "nt" "xp" );, , , } assign(f = cat([libname][1][1 .. 2], "&bsol;_$Art16_Kr9$_")), system cat(( "Ver > ", )f ); assign(v = CF2(readbytes(f, 'TEXT', ∞))), delf1(f, `*`), assign(w = D(v, t1 union t2)); if member(w t2, ) then for k in a do

f := cat(k, ":&bsol;PageFile.sys" ;) try open ,(f 'READ'); close( )f catch "file or directory does not exist": next

catch "file or directory, %1, does not exist": next catch "file I/O error" RETURN(: G(k w, )) catch "permission denied" RETURN(: G(k w, )) end try

end do elif member(w t1, ) then for k in a do f := cat(k, ":&bsol;MsDos.sys" ;) if not type( ,f 'file') then next end if; do b := readline( )f ; if b = 0 then WARNING("file MSDOS.SYS on <%1> is corrupted", k); close( )f ; break

end if; if search(CF2(b), "windir") then close( )f ;

b := FNS(b[Search(b, "=")[1] + 1 .. -1], " " 3 ;, ) break

end if

end do;

if b = 0 then next end if; try open ,(f 'READ'); close( )f catch "file or directory does not exist": next catch "file or directory, %1, does not exist": next catch "file I/O error" RETURN(: map(Case, [b[1], b], 'upper')) catch "permission denied" RETURN(: map(Case, [b[1], b], 'upper')) end try

end do; ERROR( "fatal system error: correct file MSDOS.SYS has not been found on %1", map(Case a, , 'upper'))

else ERROR ("System error: unknown host operating system <%1>", v) end if

end proc

> BootDrive(); ⇒ ["C", "C:&bsol;WINDOWS"]

При организации обработки особых и ошибочных ситуаций, возникающих при выполнении процедур доступа к файлам данных, следует обратить внимание на tracelast-команду, возвращающую как последнюю запись из стэка ошибок, так и выводящую дополнительную полезную информацию по возникшей ситуации. Данная информация может оказаться полезной при тестировании Maple-процедур. Команда tracelast позволяет получать информацию независимо от trapperror-функции, try-предложения и lasterror-переменной. Однако, она не применима в теле процедур и ее следует использовать сразу же за местом возможного появления ошибочной ситуации, ибо обеспечиваемая командой информация может быть удалена средствами сборки «муссора» пакета. Детальнее с основными ошибочными и особыми ситуациями в/в пакета Maple можно ознакомиться по ?IO_errors-конструкции.

6.3. Базовые средства Maple-языка для обеспечения доступа к внешним файлам данных TEXT-типа

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

Оболочка средств доступа: fopen, open, popen (функции открытия файлов)

TEXT-файлы

BINARY-файлы

FORMAT-файлы

writeline, readline

writebytes, readbytes

writedata, readdata

writestat, readstat

fprintf

fscanf

writeto, appendto

Оболочка средств доступа: fclose, close, pclose (функции закрытия файлов)

Общие функции доступа: feof, filepos, fremove, fflush, iostatus, system

В данной схеме выделяются три уровня: оболочка, функции непосредственного доступа к файлам и общие обслуживающие функции. Оболочка средств доступа обеспечивает функции явного открытия и закрытия файлов; при этом, в режиме открытия можно определять как тип открываемого файла (TEXT, BINARY), так и режим доступа к нему (READ, WRITE, APPEND). Хотя средства данного уровня в общем случае и не обязательны, т.к. функции непосредственного доступа (второй уровень) обеспечивают открытие файлов, а по завершении работы с пакетом все открытые в сеансе файлы автоматически закрываютя, в целом ряде случаев использование средств оболочки не только желательно, но и обязательно, позволяя обеспечивать более гибкое управление общим механизмом доступа к внешним файлам пакета. Функциональные средства оболочки достаточно детально были рассмотрены в предыдущем разделе главы.

Третий уровень составляют общие средства доступа, обеспечивающие ряд сервисных процедур по обслуживанию файлов пользователя. Набор их невелик и поддерживаемые ими функции сводятся к удалению файлов (fremove) из файловой системы компьютера, тестированию состояния открытых файлов (iostatus), а также идентификации особой ситуации «конец файла» (feof) и текущей позиции сканирования в файле (filepos) наряду с обеспечением гарантированной записи данных в файл (fflush). Вместе с тем, посредством system-функции пользователь имеет возможность непосредственно в среде пакета выполнять команды системы DOS, в частности, команды обслуживания файловой системы. Это обстоятельство позволяет вполне эффективно обходиться имеющимися у ядра пакета собственными средствами обслуживания файлов.