Все компоненты типизированного файла, в отличие от текстового файла, имеют одну и ту же длину. Это позволяет программе определить местоположение любого компонента по его номеру и осуществить прямой доступ к этому компоненту. Нумерация компонентов типизированного файла производится последовательностью чисел 0, 1, 2, 3,...
При открытии типизированного файла его указатель устанавливается на нулевой компонент. После выполнения каждой операции чтения или записи указатель сдвигается на следующий компонент.
В отличие от текстового файла, типизированный файл не содержит в себе маркера конца файла. В служебную информацию о файле операционная система записывает количество его компонентов, что и используется в дальнейшем для определения конца этого файла.
Произведем сравнение текстового и типизированного файлов по двум критериям: скорости передачи информации и объему занимаемой памяти.
Пример 1.
Var k : integer;
F1 : text;
F2 : file of integer;
Begin
Assign(F1,'F1.dat'); Assign(F2,'F2.dat');
Rewrite(F1); Rewrite(F2);
k:=1598;
Write(F1,k); Write(F2,k);
В оперативной памяти переменная k, соответствующая типу integer, занимает два байта. Значение 1598 в шестнадцатеричной записи имеет вид 063B. Компонент файла F2 также занимает два байта (тип integer). Внутреннее представление переменной k в оперативной памяти и в файле F2 одно и то же. Следовательно, никакого преобразования формы представления данных при записи в типизированный файл не происходит.
В текстовом файле, как и в строке, каждая цифра числа занимает один байт (в коде ASCII). Для значения k = 1598 в файле F1 будет отведено 4 байта. Форма представления значения k в оперативной памяти и в файле F1 различна; поэтому при записи чисел в текстовый файл некоторая часть машинного времени будет затрачиваться на преобразование формы их представления. Следовательно, скорость передачи данных в типизированном файле всегда выше, чем в текстовом файле; объем внешней памяти, занимаемой типизированным файлом, в общем случае меньше по сравнению с текстовым файлом.
Некоторым недостатком типизированного файла можно считать то, что содержание этого файла нельзя прочесть или изменить с помощью текстового редактора (в ряде случаев это достоинство, а не недостаток).
Для операций чтения и записи в типизированном файле используются процедуры Read и Write (но не Readln, Writeln). Для типизированных файлов определены также предописанные процедура Seek и функции FileSize, FilePos.
1. Процедура Seek(F, k) перемещает указатель файла F на компонент с номером k. Переменная k должна иметь тип longint.
2. Функция FileSize(F):longint возвращает текущий размер файла F (количество компонентов файла).
3. Функция FilePos(F):longint возвращает номер текущей позиции файла F.
С учетом способа нумерации компонентов типизированного файла последний его компонент имеет номер FileSize(F)-1.
Примеры использования процедуры Seek и функций FileSize, FilePos:
Seek(F,0) - установка указателя на первый компонент файла F (на компонент с нулевым порядковым номером);
Seek(F,FileSize(F)) - установка указателя на конец файла F для дописывания новых компонентов;
Seek(F,FilePos(F)+1) - пропуск компонента файла.
Процедурой Read вводится из типизированного файла полностью один компонент вне зависимости от того, является он простым или составным (из текстового файла составные переменные вводятся поэлементно). Процедура Write записывает в типизированный файл также один компонент вне зависимости от его типа.
Как и для текстового файла, процедура Read(F,a,b,c) эквивалентна следующей последовательности процедур:
Следует обратить внимание, что в списке вывода процедуры Write могут быть только переменные того же типа, что и тип компонента файла (но не константы, функции или выражения).
Пример 2.
VarF1 : file of integer;
Begin
Assign(F1,'F1.dat');
Rewrite(F1);
Write(F1,5);
При трансляции фрагмента, приведенного в примере 2, будет получено сообщение "Error 20: Variable identifier expected" (отсутствует идентификатор переменной), поскольку в процедуре Write указана константа, а не переменная.
Причина запрета использования констант в процедуре Write состоит в следующем. Как было ранее указано, при записи в типизированный файл содержимое поля памяти полностью переписывается в компонент файла, т.е. преобразование этого содержимого не производится. В программе для числовой константы отводится минимально необходимое поле памяти, что не гарантирует совпадение ее типа с типом компонента файла. В частности, в примере 2 константа 5 будет занимать один байт памяти, в то время как компонент файла по описанию имеет размер 2 байта.
Пример 3.
Type Ar = array[1..100] of real;
RecType = record
a,b : real;
m,n : integer;
S : string
end;
Var i : byte;
P,Q,R : Ar;
Rec : array[1..10] of RecType;
F1 : file of Ar;
F2 : file of RecType;
Begin
Assign(F1,'F1.dat'); Assign(F2,'F2.dat');
Reset(F1); Reset(F2);
Read(F1,P,Q,R);
Fori:=1 to10 do
Read(F2,Rec[i]);
Компонентами файла F1 являются массивы типа Ar, файла F2 - записи типа RecType. При обращении к файлу F1 читается полностью один массив (P, Q или R), к файлу F2 - запись, являющаяся компонентом массива записей Rec.
Пример 4.
Var S : string[66];
F : file of string[66];
Begin
Assign(F,'F.dat');
Rewrite(F);
S:='0123456789';
Write(F,S);
...................
При трансляции этого фрагмента будет выдано сообщение "Error 26: Type mismatch" (несоответствие типов). Причиной является то, что для переменной S и компонента файла F использовано описание, а не имя типа, в связи с чем компилятор формально считает их типы не соответствующими друг другу. Отмеченная ошибка, обнаруживаемая при трансляции, аналогична следующему:
VarA : array[1..66] of byte;
B : array[1..66] ofbyte;
Begin
B:=A;
Здесь также будет сообщение этапа компиляции о несоответствии типов.
Правильная запись примера 4:
Type string66 = string[66];
FileString = file of string66;
Var S : string66;
F : FileString;
Begin
Assign(F,'F.dat');
Rewrite(F);
S:='0123456789';
Write(F,S);
...................
Примечание. Пример 4 подтверждает одно из правил структурного программирования: в разделе Var всегда нужно использовать имена типов, а не их описания.