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