Кроме текстовых файлов в языке Паскаль существует ещё два типа файлов – типизированные и бестиповые файлы. Их отличия от текстовых файлов состоят в способе ввода/вывода информации, в возможности прямого доступа к элементам файла и – для типизированных файлов – ограничениях на тип хранящейся информации.
Типизированный файл представляет собой последовательность элементов одного и того же типа. Для объявления типизированного файла используется следующий синтаксис:
type <имя типа файла> = file of <тип>;
Имя типа файла должно быть правильным идентификатором, а тип – любым типом фиксированного размера. Таким образом, элементами типизированного файла не могут быть динамические типы, такие как строки и динамические массивы, переменные типа Variant, а также другие файлы. При этом можно определить типизированный файл, содержащий короткие строки или статические массивы.
Принципиальное отличие типизированного файла от текстового состоит в способах ввода и вывода информации. При выводе информации в текстовый файл внутренний формат данных, используемый компьютером, преобразуется в текстовый формат, понятный человеку. Например, целые числа преобразуются в последовательность десятичных цифр, вещественные числа – в последовательность из цифр, точки, знака «минус», логические значения – в последовательность символов TRUE или FALSE. Кроме того, числа должны отделяться друг от друга пробелами и символами перевода строки – в противном случае их невозможно будет прочитать, а также ввести. При вводе данных происходит обратная операция – выделяется последовательность символов, составляющая одно число, и эта последовательность символов преобразуется во внутренний формат числа. Таким образом, текстовые файлы обладают двумя недостатками – во-первых, на преобразования необходимо время, а во-вторых, найти, например, пятое число в файле затруднительно, поскольку длина последовательности символов для представления числа может быть разной. Правда, текстовые файлы могут быть прочитаны человеком, но в некоторых случаях это несущественно – если файл используется некоторой программой, то вполне вероятно, что человеку нет необходимости туда заглядывать. В этом случае можно использовать преимущества типизированных файлов.
16432 // Число в 10-ой системе счисления
// В текстовом файле будут символы '1', '6', '4', '3', '2'
00004030h // Число в 16-ой системе счисления
0@NULNUL // Символы в типизированном файле (байты в обратном порядке)
// '0' – код 48 (30h), '@' – код 64 (40h)
Для работы с типизированным файлом, прежде всего, необходимо объявить файловую переменную. Затем эта переменная связывается с файлом на диске с помощью функции AssignFile и открывается с помощью функции Reset или Rewrite. При использовании текстового файла функция Reset открывает файл только для чтения, а функция Rewrite – только для записи. Типизированный файл независимо от используемой функции открывается в режиме «чтение и запись». Однако функция Reset требует, чтобы файл существовал, а функция Rewrite создаёт файл, если он не существует, и стирает содержимое файла, если он существует.
Для чтения из типизированного файла используется функция Read, а для записи в типизированный файл – функция Write. Функции ReadLn и WriteLn не применимы к типизированным файлам, поскольку никаких переводов строки в типизированном файле не предполагается. Записываются и, соответственно, читаются данные только одного типа, указанного при объявлении файла.
Для закрытия типизированного файла, как обычно, используется функция CloseFile.
Как уже было сказано, типизированный файл представляет собой последовательность элементов одного и того же типа. Элементы файла имеют один и тот же размер, что даёт возможность прямого доступа к любому элементу файла.
procedure Seek(var f: file; n: integer);
Параметр f задаёт файловую переменную, а параметр n – номер элемента в файле. Элементы нумеруются с 0. Процедура Seek перемещает указатель на элемент с указанным номером. При чтении этот элемент будет прочитан, а при записи – перезаписан. Процедура Seek может переместить указатель и за конец файла. Записывать данные в такую позицию можно, а при чтении возникает ошибка.
function FileSize(var f: file): integer;
function FilePos(var f: file): integer;
Функция FileSize возвращает размер файла в элементах. Функция FilePos возвращает позицию чтения/записи файлах. Для типизированного файла такая позиция может находиться только в начале элемента, поэтому функция FilePos возвращает номер элемента. Обе функции могут использоваться, только если файл открыт.
type
TypedFile = file of integer;
var
f: TypedFile;
a: array of integer;
n, i: integer;
a1, a2: integer;
begin
// Чтение динамического массива из типизированного файла
AssignFile(f, 'file.dat');
Reset(f);
n := FileSize(f);
SetLength(a, n);
for i := 0 to n - 1 do
read(f, a[i]);
CloseFile(f);
// Запись массива в типизированный файл
AssignFile(f, 'file.dat');
Rewrite(f);
for i := 0 to n - 1 do
write(f, a[i]);
CloseFile(f);
// Обмен записей с номерами 3 и 7. Здесь наличие таких записей не проверяется
AssignFile(f, 'file.dat');
Reset(f);
seek(f, 3);
read(f, a1);
seek(f, 7);
read(f, a2);
seek(f, 3);
write(f, a2);
seek(f, 7);
write(f, a1);
CloseFile(f);
end.
Бестиповые файлы представляют собой низкоуровневый канал ввода/вывода, используемый обычно для прямого доступа к дисковым файлам, независимо от типа и структуры данных, хранящихся в нём. Файловая переменная для бестипового файла объявляется с помощью ключевого слова file без каких-либо дополнительных описаний.
var f: file;
Далее как обычно необходимо связать файловую переменную с файлом на диске с помощью функции AssignFile. Затем файл открывается с помощью функции Reset или Rewrite.1 Также как и типизированный, бестиповый файл независимо от используемой функции открывается в режиме «чтение и запись». После окончания работы файл закрывается функцией CloseFile.
Для чтения из бестипового файла используется функция Read, а для записи в типизированный файл – функция Write.2 Также как и к типизированным файлам, функции ReadLn и WriteLn не применимы к бестиповым файлам. В бестиповый файл, в отличие от типизированного, можно записать данные разных типов.
var
f: file;
i: integer = -5;
r: real = 5.55;
c: char = '!';
b: byte = 5;
o: boolean = true;
begin
// Записываем в бестиповый файл переменные разных типов
AssignFile(f, 'file.dat');
Rewrite(f);
write(f, i, r, c, b, o);
CloseFile(f);
// Считываем из файла те же переменные, потом записываем в конец файла переменную r
AssignFile(f, 'file.dat');
Reset(f);
read(f, i, r, c, b, o);
write(f, r);
CloseFile(f);
writeln(i, ' ', r, ' ', c, ' ', b, ' ', o);
AssignFile(f, 'file.dat');
Reset(f);
seek(f, 12); // Перемещаем указатель на элемент с номером 12. Поскольку элементы нумеруются с 0,
// и в бестиповом файле элементы соответствуют одному байту, мы пропускаем 12 байт,
// т.е. две первые переменные (целого и вещественного типа), и попадаем на символьную переменную.
read(f, b); // Далее мы считываем эту переменную как переменную типа byte, и получаем 33 – код символа '!'
CloseFile(f);
writeln(b);
end.
1 В Borland Developer Studio в этих функция необходимо указать размер записи, используемый при передаче данных. По историческим причинам по умолчанию этот размер равен 128 байтам. Единственный размер записи, который будет подходить для любого файла, – 1.
2
В Borland Developer Studio используются функции BlockRead и BlockWrite.
function BlockRead(var f: file; var buf: type; count: integer): integer;
function BlockWrite(var f: file; var buf: type; count: integer): integer;