Наконец, второй уровень представляет собственно функциональные средства непосредственного доступа к внешним файлам пакета, обеспечивая операции записи и чтения информации. Данные средства как в плане их основной функциональной нагрузки, так и в плане изложения целесообразно разделить на три группы, обеспечивающие работу с файлами соответственно типов TEXT, BINARY и FORMAT. Первые две группы файлов стандартно определяются ядром пакета и для непосредственного доступа к ним имеется ряд встроенных функций. Тогда как третий тип определен нами условно и пакетом явно не поддерживается, однако он введен нами для более четкого представления общей схемы организации доступа к внешним файлам пакета. Более того, в целом ряде случаев классифицированные нами по трем группам средства могут функционально взаимно перекрываться, однако это вопрос отдельного рассмотрения. Суть каждого из указанных типов доступа к файлам будет рассматриваться ниже, сейчас же мы переходим к обсуждению средств непосредственного доступа к широко используемым в среде языка файлам TEXT-типа.
По функции доступа writeline(<СФ>, S1 ,S2, ..., Sn) производится запись в указанный первым фактическим СФ-аргументом файл строчных Sk-выражений, разделяемых управляющим символом hex(0D0A) «перевода строки и возврата каретки». В случае отсутствия второго фактического аргумента в файл помещается пустая строка, т.е. один управляющий hex(0D0A)-символ. Успешное завершение вызова writeline-функции возвращает общее число записанных за одну операцию символов. При указании в качестве приемного файла стандартных каналов default либо terminal запись производится на приписанные им при загрузке ядра пакета системные устройства/каналы. При этом, если же файл предварительно был открыт в READ-режиме и является файлом {STREAM|RAW}вида, то по writeline-функции он переоткрывается в WRITE-режиме доступа как файл TEXT-типа с сохранением последней позиции сканирования в качестве текущей. То же самое происходит и в случае закрытого файла. При этом, если writeline-функция применяется к закрытому файлу, то он полностью обновляется, в противном случае производится дозапись в его текущую сканируемую позицию, т.е. реализуется APPEND-режим.
По обратной к предыдущей readline(<СФ>)-функции производится чтение очередной записи-строки из указанного фактическим СФ-аргументом файла, где в качестве значения СФ-аргумента (подобно другим функциям доступа) может выступать как спецификатор файла, так и номер приписанного ему открытого логического канала в/в. Успешный вызов readline-функции возвращает либо действительную строку без завершающего ее управляющего hex(0D0A)-символа, либо нулевое значение, идентифицирующее ситуацию «конец файла (eof)». При этом, во втором случае файл закрывается, если в качестве аргумента readline-функции был указан спецификатор файла. Следующий фрагмент иллюстрирует использование рассмотренных функций доступа к внешним файлам:
> F:="C:/tmp/trg": n:=fopen(F, WRITE): for k to 5 do writeline(n, "Str"||k) end do: close(n);
> n:= fopen(F, READ): s:= NULL: while not Fend(n) do s:=s, readline(n)) end do: s, close(n);
"Str1", "Str2", "Str3", "Str4", "Str5"
> n:= fopen(F, APPEND): for k to 5 do writeline(n, "Str_"||k) end do: close(n);
> n:= fopen(F, READ): s:= NULL: while not Fend(n) do s:= s, SUB_S(["\n"=""], readline(n)) end do: s, close(n);
"Str1", "Str2", "Str3", "Str4", "Str5", "Str_1", "Str_2", "Str_3", "Str_4", "Str_5"
> n:=fopen(F, READ): s:=NULL: while not feof(n) do s:=s,readline(n) end do: s, close(n);
"Str1", "Str2", "Str3", "Str4", "Str5", "Str_1", "Str_2", "Str_3", "Str_4", "Str_5", 0
В данном фрагменте посредством writeline-функции в цикле создается файл, содержащий 5 записей-строк. После закрытия посредством функции readline возвращается его содержимое. Затем после закрытия файл вновь открывается в APPEND-режиме доступа для дозаписи информации в его конец. Дозапись производится в цикле, расширяя уже существующий файл еще на 5 записей. В завершении файл открывается на чтение для вывода его обновленного состояния. В данном фрагменте рекомендуется обратить внимание на использование нашей процедуры Fend для обработки особой ситуации «конец файла» вместо стандартной функции feof, которая не обеспечивает в ряде конструкций приемлемого результата, как это иллюстрирует последний пример фрагмента.
При каждом новом обращении к readline-функции считывается очередная строка файла и указатель (сканирующий позицию в файле) устанавливается на начало записи, следующей за считанной. По достижении указателем конца файла функция возвращает нульзначение; в случае невозможности выполнить очередную операцию чтения инициируется ошибочная ситуация. Если файл, к которому применяется readline-функция, оказывается закрытым, то он открывается как TEXT-файл в READ-режиме доступа. Функция readline может использоваться в составе более сложных конструкций на правах обычной функции, возвращающей в качестве результата очередное считанное значение типа string. Следующий фрагмент представляет процедуру Nstring, возвращающую строку с указанным вторым фактическим аргументом номером из заданного первым аргументом файла TEXT-типа. В качестве второго аргумента могут выступать множество либо список номеров искомых строк, возвращаемых в виде списка.
Nstring := proc(F::{string, symbol }, S::{set(posint), list(posint)}) local k p s f, , , , ω ω1 ω2 ν ν1, , , , ; `if`(type(F, 'file') and type(F, 'rlb'), `if`(Empty(S), ERROR "the second argument is empty"( ), NULL), ERROR("<%1> is not a file or has a type different from TEXT", F)); ω1, p, k := ( ) → WARNING("all required lines are absent in file") [, Close(F)], 0; ω2 ν1, := ν → WARNING("lines with numbers %1 are absent in file", ν), ( ) → `if`(type ,(f 'list'), true false, ); `if`(nargs = 3 and type(eval args[3]( ), {'string', 'symbol'}), [ assign67(ω = interface(warnlevel)), null(interface(warnlevel = 0)), assign(f = MkDir(args 3[ ], 1))], assign(f = [ ])); assign(' 'p = fopen(F, 'READ', 'TEXT'), ν = {op(S)}), `if`(ν1( )f , 1, null(interface(warnlevel = ω))); while not Fend(p) do [assign('s' = readline(p), 'k' = k + 1)]; if member(k, ν) then `if`(ν1( ), assign(' 'f = [op( )f , s]), writeline ,(f s)); ν := ν minus { }k end if end do; if ν = {op(S)} then RETURN(ω1( ), `if`(ν1( ), f, fremove(f)), Close(F)) elif ν ≠ { } then ω2 ν( ), `if`(ν1( )f , RETURN ,(f Close(F)), NULL) else end if; Close(F), `if`(ν1( )f , ,f op([WARNING("the resultant file is in <%1>", f), Close(f), f])) end proc > Nstring("C:/RANS/TRG.txt", [7, 14, 17, 56, 61]); Warning, lines with numbers {56, 61} are absent in file ["7aaaaaaaaaa", "17aaaaaaaa", "14aaaaaaa"] > Nstring("C:/RANS/TRG.txt", [7, 14, 17], "C:/Temp/Order/ABS.txt"); Warning, the resultant file is in <c:\temp\order\abs.txt> "c:\temp\order\abs.txt" |
В случае отсутствия искомой записи возвращается соответствующее диагностическое сообщение. Тогда как третий необязательный аргумент позволяет определять приемный файл для указанных строк-записей исходного F-файла данных.
Следующий фрагмент представляет полезную процедуру FTabLine, обеспечивающую более эффективную обработку больших TEXT-файлов данных различного назначения.
FTabLine := proc(F::file) local d k h m n p T x y t avz, , , , , , , , , , , ω; assign(ω = cat(F, ".m"), ν = cat(``, sstr [( "." = "_"], CFF(F)[-1], avz), "_fldt")), `if` type(( ω, 'file'), (proc() read ω; RETURN(WARNING("the FLDT has been activated as <%1>", ν)) end proc )( ), 7); `if` type( ,( F 'rlb'), assign(k = 1, T[1] = 0, m = 0, n = ∞, Close(F), t = fopen(F, 'READ', 'TEXT')), ERROR("<%1> has a type different from TEXT", F)); while not Fend(t) do readline(t); k := k + 1; T[k] := filepos(t) end do; for k to nops(op 2,( eval(T))) − 1 do T k[ ] := [T k[ ], T[k + 1] − 3] end do; Close(F), (proc( )t T t[ ] := ' [ ]'T t ; NULL end proc )( )k , table(op 2,( eval(T))), null `if`( (1 < nargs and args 2[ ] ≠ 'FLDT', [ assign(d = nops(op 2,( eval(T)))), add _1N 0, [( ( assign('p' = T[k][2] − T[k][1] + 1), `if`(m < p, assign(' 'm = p, ' 'x = [k p, ]), 1), `if`(p < n, assign(' 'n = p, ' 'y = [k p, ]), 1 ])) , k = 1 .. d), assign(args 2[ ] = [d y x, , ])], 1)); if member '( FLDT', {args}) then save1(cat(``, sstr(["." = "_"], CFF(F)[-1], avz), "_fldt"), T, ω); eval(T), WARNING "the FLDT for file <%1> has been saved in file <%2>,"( F, ω), unassign(ν) else eval(T) end if end proc > GenFT("C:/Temp/Veeroj.SV", 61, 20); T:= FTabLine("C:/Temp/Veeroj.sv", 'FLDT'); Warning, the resultant file is in <c:\temp\veeroj.sv> [1, 58, 666] Warning, the saving result is in datafile <c:/temp/veeroj.sv.m> Warning, the FLDT for file <c:/temp/veroj.sv> has been saved in file <c:/temp/veroj.sv.m> T := table([1 = [0,0], 2 = [3, 8], 3 = [11, 64], 4 = [67, 77], 5 = [80,116], 6 = [119,167], 7 = [170, 201], 8 = [204, 240], 9 = [243, 300], 10 = [303, 351], 11 = [354, 382], 12 = [385, 386], 13 = [389, 415], 14 = [418, 467],15 = [470, 518], 16 = [521, 563], 17 = [566, 594], 18 = [597, 647], 19 = [650, 660], 20 = [663, 663]]) > FTabLine("C:/Temp/Veeroj.sv", 'h'): h; Warning, the FLDT has been activated as <veeroj_sv_fldt> [20, [1, 1], [9, 58]] > eval(veeroj_sv_fldt); T := table([1 = [0,0], 2 = [3, 8], 3 = [11, 64], 4 = [67, 77], 5 = [80,116], 6 = [119,167], 7 = [170, 201], 8 = [204, 240], 9 = [243, 300], 10 = [303, 351], 11 = [354, 382], 12 = [385, 386], 13 = [389, 415], 14 = [418, 467],15 = [470, 518], 16 = [521, 563], 17 = [566, 594], 18 = [597, 647], 19 = [650, 660], 20 = [663, 663]]) |
Вызов процедуры FTabLine(F) возвращает специальную таблицу диспозиции строк файла
(FLDT), чьими входами являются номера строк TEXT-файла, заланного F-аргументом, тогда как выходами являются 2-элементные списки, чьи элементы определяют начальные и конечные позиции соответствующей строки в файле F. При этом, при кодировании необязательного второго аргумента через него возвращается 3-элементный список вида [d, [k, Min], [p, Max]], где: d – число строк в файле F и k, p – номер строки с минимальной и максимальной длиной соответственно. Знание данной информации, в частности, позволяет организовывать быстрый доступ к строкам файла данных не последовательно, а по номерам строк, реализую своего рода индексный метод доступа для достаточно больших файлов данных TEXT-типа.