Страница 13 из 16
8. БД на плоских файлах 8.1 Я хочу какую-нибудь простейшую БД и прямо сейчас! Вы можете использовать простой текстовый файл с разделителями. Например, если мы пишем нечто типа телефонной книги, то вполне вероятно предположить, что ни в чьем имени, ни в номере телефона не встретится последовательность ::, так что именно ее и можно использовать в качестве разделителей. Файл с данными может выглядеть так: phones.data Иванов И.И.::888-0000::Какая-то улица, 17, кв 40 Сидоров П.И.::888-8429::Другая улица, 5, кв 21 ...... и тд.
тогда программа, которая читает данные, может быть примерно такого вида: dump_phones.pl #!/usr/bin/perl $filename = 'phones.data'; # открываем файл open DATA, $filename or die "Невозможно открыть $filename: $!";
# читаем построчно из файла while (<DATA>) { chomp; # удаление символа конца строки # теперь в $_ есть строка и мы ее разделяем на переменные ($name, $phone, $address) = split(/::/); # и выведем на печать print "Имя: $name, телефон: $phone, адрес: $address\n"; } close DATA;
Больше проблем возникает в случае, если надо удалить или отредактировать запись, но и их можно довольно просто и элегантно решить, если использовать механизм редактирования на месте (inplace edit) -- при использовании операции "ромб"(<>), можно читать из одного файла, а писать в другой: change_phones.pl #!/usr/bin/perl $^I = '~'; # запускаем inplace edit while (<>) { # Обратите внимание, что мы не открывали файл: при такой #конструкции имя файла берется из командной строки chomp; ($name, $phone, $address) = split(/::/); if (.... некоторое условие, при котором мы оставляем наши данные ... ) { print "$name::$phone::$address\n"; # теперь данные есть в новом файле } }
если запустить это программу как change_phones.pl phones.data,
то в текущем каталоге будут два файла: phones.data, с записями, которые удовлетворили нашим условиям и phones.data -- предыдущая копия. Также, во многих случаях, всю программу такого типа можно записать как one-liner: perl -i~ -n -e 'print if(... условие)' Двоичные файлы Для чтения двоичных файлов в Perl можно использовать функции read и unpack. К примеру, если использовать двоичный файл для хранения телефонной книги такого формата: 40 символов -- фамилия, И.О. 10 символов -- номер телефона, 60 символов -- адрес, то строка описания формата для unpack будет выглядеть так: $format_str = 'A40 A10 A60'
, а сама программа, аналогичная первому примеру: binary_phones.pl #!/usr/bin/perl $format_str = 'A40 A10 A60'; open DATA, 'binary.dat' or die "$!"; while (read(DATA, $buf, 40+10+60)) { # <DATA> не покатит: такая # конструкция будет читать до символа перевода строки, а это не то, что нужно ($name, $phone, $address) = unpack($format_str, $buf); # Теперь в $name, $phone, $address есть данные и с ними можно делать # все, что захочется } close DATA;
Чтобы вывести в файл такую запись можно использовать конструкцию типа print FILE pack($format_str, $name, $phone, $address); 8.2 Можно ли как-нибудь из Perl получить доступ к dbf файлам? Да, можно. На https://www.fi.muni.cz/~adelton/ есть модуль XBase, который позволяет читать/писать dbf. При чтении он даже поддерживает индексы. Кроме того, в комплект поставки также входит модуль DBD::XBase, при помощи которого можно оперировать dbf на SQL (более подробно про DBI -- далее). 8.3 А к MS access .mdb? К файлам MS Access нельзя обращаться из perl напрямую, по крайней мере, в настоящее время. К MS Access можно обращаться по ODBC, при помощи DBD::ODBC. 8.4 Зачем и как нужно запирать (lock) файлы? Представьте себе ситуацию когда одновременно работают несколько копий одной и той же программы (к примеру, cgi-скрипты, обслуживающие запросы), читающие/пишущие в один файл, тогда рано или поздно возникнет ситуация при которой один скрипт прочитал данные, произвел над ними некоторые действия и собрался записать их назад в файл, но в это же время другой скрипт тоже прочитал данные, тоже произвел над ними действия, но (!) он прочитал старые данные, которые он и запишет поверх данных, выданных другим скриптом. Таким образом, в файле останутся данные записанные одним из скриптов -- в лучшем случае, в худшем -- структура файла будет испорчена. Чтобы этого избежать в Unix и большинстве других ОС есть системный вызов flock(2) или аналогичный. Как использовать flock К примеру, скрипт который записывает имена вызывающих хостов в файл. (На деле такой список, конечно, можно получить из журнала регистрации web-сервера). lock_exm.pl #!/usr/bin/perl use Fcntl; # Импорт констант open (HOSTS, '>>hosts.log'); # Файл открыт для добавления записи flock(HOSTS, LOCK_EX); # Теперь файл заблокирован: Если любой другой скрипт тоже вызовет flock на # этом файле, его flock не вернет управление в программу, пока мы не # разблокируем файл. Обратите внимание: flock -- декларативная функция, если # один из скриптов ее не использует при записи, то вся ваша блокировка не # работает. print HOSTS $ENV{REMOTE_HOST}, "\n"; # записали строку close HOSTS; # Файл при закрытии разблокируется автоматически
# Вывести сообщение для пользователей print "Content-Type: text/plain\n\n"; print "Название вашего хоста записано\n";
Более подробный рассказ о flock и пример доступны на https://w3.stonehenge.com/merlyn/WebTechniques/col04.html 8.5 Чего делать на системах Судя по perlfaq5(1), можно использовать модуль File::Lock с CPAN.
|