Бинарные файлы
Механизм использования записи с вариантной частью
Описание записи с вариантной частью
Запись с вариантной частью
Вложенные операторы with
Оперирование несколькими полями
Если программе предстоит несколько раз подряд обращаться к полям одной и той же записи, может оказаться неудобным записывать это обращение полностью:
my_birthday.day:= 17;
my_birthday.month:= 3;
my_birthday.year:= 2004;
Для сокращения таких участков служит оператор with, позволяющий обращаться к полям, не указывая каждый раз имя всей записи:
with <имя_записи> do
begin <операторы>
{имена полей здесь используются как <имя_поля>,
а не как <имя_записи>.<имя_поля>}
end;
Например:
with my_birthday do
begin day:= 17;
month:= 3;
year:= 2004;
end;
Замечание. Для того чтобы внутри оператора with можно было обратиться не к полю записи, а к глобальной переменной с таким же именем, перед этой переменной нужно указать (через точку) имя программы: <имя_программы>.<имя_переменной>.
Например:
with my_birthday do
begin day:= 17;
month:= 3; {поле записи birthday.month}
year:= 2004;
programma.month:= 5; {глобальная переменная month}
end;
Если возникает необходимость расположить один оператор with внутри другого, то любую переменную (если перед ней явно не указано имя записи ), находящуюся под внутренним оператором with, компилятор пытается интерпретировать в такой последовательности:
- если во внутренней записи есть поле с искомым именем, то поиск заканчивается;
- если во внутренней записи поля с таким именем нет, то поиск производится среди полей внешней записи (если вложенных операторов with больше, чем два, то поиск ведется последовательно во всех задействованных записях в направлении "изнутри наружу");
- если среди полей всех вложенных записей нет искомого идентификатора, компилятор считает его глобальной переменной.
Например:
type date = record day: 1..31;
month: 1..12;
year: 1900..2005;
end;
student = record name: string[100];
year: 1950..2005; {год поступления}
gruppa: string[5];
birth: date;
end;
var ivanov: student;
begin
...
with ivanov do
begin
...
with birth do
begin
...
year:= 2001; {birth.year}
gruppa:= 'IT01'; {ivanov.gruppa}
...
end;
...
end;
end;
Если заранее известно, что в массиве записей (таблице) некоторые поля могут оставаться пустыми (наборы пустых полей могут быть разными для разных записей ), то вполне понятно желание как-то сократить неиспользуемый, но занимаемый объем памяти.
Специально для таких случаев существуют записи с вариантной частью.
В разделе var запись с вариантной частью описывают так:
var <имя_записи>: record <поле1>: <тип1>;
[<поле2>: <тип2>;]
[...]
case <поле_переключатель>: <тип> of
<варианты1>: (<поле3>: <тип3>;
<поле4>: <тип4>;
...);
<варианты2>: (<поле5>: <тип5>;
<поле6>: <тип6>;
...);
[...]
end;
Невариантная часть записи (до ключевого слова case) подчиняется тем же правилам, что и обычная запись. Вообще говоря, невариантная часть может и вовсе отсутствовать.
Вариантная часть начинается зарезервированным словом case, после которого указывается то поле записи, которое в дальнейшем будет служить переключателем. Как и в случае обычного оператора case, переключатель обязан принадлежать к одному из перечислимых типов данных (см. лекцию 3). Список вариантов может быть константой, диапазоном или объединением нескольких констант или диапазонов. Набор полей, которые должны быть включены в структуру записи, если выполнился соответствующий вариант, заключается в круглые скобки.
Пример. Для того чтобы описать содержимое библиотеки, необходима следующая информация:
Для книг | Для газет | Для журналов |
Автор | Название | Название |
Название | Дата выхода (день, месяц, год) | Год и месяц издания |
Год издания | Издательство | Номер |
Издательство | - | Издательство |
Графы "Название" и "Издательство" являются общими для всех трех вариантов, а остальные поля зависят от типа печатного издания. Для реализации этой структуры воспользуемся записью с вариантной частью:
type biblio = record
name,publisher: string[20];
case item: char of
'b': (author: string[20]; year: 0..2004);
'n': (data: date);
'm': (year: 1700..2004;
month: 1..12;
number: integer);
end;
В зависимости от значения поля item, в записи будет содержаться либо 4, либо 5, либо 6 полей.
Количество байтов, выделяемых компилятором под запись с вариантной частью, определяется самым "длинным" ее вариантом. Более "короткие" наборы полей из других вариантов занимают лишь некоторую часть выделяемой памяти.
В приведенном выше примере самым "длинным" является вариант ' b ': для него требуется 23 байта (21 байт для строки и 2 байта для целого числа). Для вариантов ' n ' и ' m ' требуется 4 и 5 байт соответственно (см. таблицу).
name, publisher | item | Вариантная часть | ||||
... | 'b' | author | year | |||
... | 'n' | data | ||||
... | 'm' | year | month | number | ||
... | 'b' | author | year | |||
Бинарные файлы хранят информацию в том виде, в каком она представлена в памяти компьютера, и потому неудобны для человека. Заглянув в такой файл, невозможно понять, что в нем записано; его нельзя создавать или исправлять вручную - в каком-нибудь текстовом редакторе - и т.п. Однако все эти неудобства компенсируются скоростью работы с данными.
Кроме того, текстовые файлы относятся к структурам последовательного доступа, а бинарные - прямого. Это означает, что в любой момент времени можно обратиться к любому, а не только к текущему элементу бинарного файла.