Вы можете использовать простой текстовый файл с разделителями. Например, если
мы пишем нечто типа телефонной книги, то вполне вероятно предположить, что ни
в чьем имени, ни в номере телефона не встретится последовательность ::, так
что именно ее и можно использовать в качестве разделителей.
Файл с данными может выглядеть так:
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;
Чтобы вывести в файл такую запись можно использовать конструкцию типа
Да, можно. На
http://www.fi.muni.cz/~adelton/ есть модуль XBase, который
позволяет читать/писать dbf. При чтении он даже поддерживает индексы.
Кроме того, в комплект поставки также входит модуль DBD::XBase, при помощи
которого можно оперировать dbf на SQL (более подробно про DBI -- далее).
Представьте себе ситуацию когда одновременно работают несколько копий одной и
той же программы (к примеру, 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";