Базы данных произвольного доступа с записями фиксированной длины
Еще одна форма хранения данных — файл на диске, предназначенный для записей фиксированной длины. В зтой схеме данные состоят из ряда записей одинаковой длины. Нумерация зтих записей либо не имеет значення, либо определяется по какой-нибудь схеме индексации.
Например, у нас может быть ряд записей со следующими данными:
40 символов — имя, один символ — инициал, 40 символов — фамилия и двухбайтовое целое — возраст. Таким образом, длина каждой записи состав-ляет 83 байта. Если бы мы читали все зти данные в базе данных, то делали бы зто порциями по 83 байта до тех пор, пока не добрались до конца. Если бы мы хотели перейти к пятой записи, то мы пропустили бы четыре раза по 83 байта (332 байта) и прочитали бы непосредственно пятую запись.
Perl поддерживает программы, которые используют файл с подобными записями. Помимо того, что вы уже знаєте, понадобятся еще несколько операций:
1. Открытие файла на диске для чтения и записи.
2. Переход в зтом файле на произвольную позицию.
3. Выборка данных фиксированной длины, а не до следующего символа новой строки.
4. Запись данных блоками фиксированной длины.
В функции open перед спецификацией, задающей способ открытия файла (для чтения или записи), необходимо записать знак плюс, указав таким образом, что данный файл в действительности открывается и для чтения, и для записи. Например:
open (А, "+<Ь"); # открьеть файл b для чтения-записи (ошибка, если файл отсутствует)
open(C, "+>d"); # создать файл d с доступом для чтения-записи
open(Е, "+”f"); # открить или создать файл f с доступом для чтения-записи
Отметим, что все, что мы сделали — зто добавили знак плюс к специфи-кации, задающей направление ввода-вывода данных в файл.
Открыв файл, мн должны перейти на определенную позицию в нем. Зто делается с помощью функции seek, которая принимает те же три параметра, что и библиотечная програм ма./yeeA^.?/ Первый параметр — зто дескриптор файла, а второй параметр задает смещение, которое интерпретируется в совокупности с третьим параметром. Как правило, в качестве третього параметра ставится нуль, чтобы второй параметр задавал абсолютную позицию для следующего чтения из файла или записи в файл. Например, чтобы перейти к пятой записи в дескрипторе файла names (как описано выше), можно сделать так:
seek(NAMES,4*83,0) ;
После перемещения указателя в файле на нужную позицию следующая операция ввода или вывода будет начинаться с зтой позиции. Для вывода используйте функцию print, но не забудьте, что записываемые данные должны иметь строго определенную длину. Чтобы сформировать запись правильной длины, можно воспользоваться функцией pack::
print NAMES pack("A40 A A40 s", $first, $middle, $last, $age);
В данном случае pack задает 40 символов для $ first, один символ — для $middle, еще 40 символов — для $last и короткеє целое (два байта) для $аде. Определенная таким образом запись будет иметь в длину 83 байта и начинаться с текущей позиции в файле.
Наконец, нам нужно узнать, как выбрать конкретную запись. Конструк-ция <names> возвращает все данные, начиная с текущей позиции і до следующего символа новой строки, однако в нашем случае предполагасгея, что данные занимают 83 байта й, вероятно, символ новой строки непосред-ственно в записи отсутствует. Позтому вместо нее мы используем функцию read, которая по внешнему виду и принципу работы очень похожа на свою UNIX-коллегу:
$count = read(NAMES, $buf, 83);
Первый параметр функции read — дескриптор файла. Второй параметр — зто скалярная переменная, в которую будут записаны прочитанные данные. Третий параметр задает количество байтов, которые нужно прочитать. Возвращает функция read количество фактически прочитанных байтов; как правило, оно равно затребованному количеству байтов, если только дескриптор файла открыт и если вы не находитесь слишком близко к концу файла.
Получив зти 83-символьные данные, разбейте их на компоненты с помощью функции unpack:
($first, $middle, $last, $age) = unpack("A40 A A40 s", $buf);
Как видно, строки, определяющие формат, в функциях pack и unpack — одинаковы. В большинстве программ зту строку заносят в переменную, указы-ваемую в начале программы, и даже вычисляют с помощью функции pack длину записей, а не используют везде константу 83:
$names = "А40 А А40 s";
$names_length = length(pack($names)); # вероятно, 83