Собственно, начиная с этого урока мы будем изучать встроенные в Perl функции (до этого мы изучали операторы), и начнем с функций, которые позволяют нам работать с файлами.
Дескриптор файла
Дескриптор файла в Perl-программе — это имя соединения для ввода-вывода между вашим Perl-процессом и внешним миром. Имена дескрипторов файлов похожи на имена помеченных блоков, но они берутся из другого пространства имен (поэтому у вас может быть скаляр $fred, массив $fred, хеш %fred, метка fred, а теперь и дескриптор файла fred). Как и метки блоков, дескрипторы файлов используются без специального префиксного символа, поэтому их можно спутать с существующими или возможными в будущем зарезервированными словами (для команд, подпрограмм и др.). Рекомендую составлять дескрипторы файлов только из прописных букв. Во-первых, они будут хорошо выделяться в тексте программы, и, во-вторых, благодаря этому программа не даст сбой при введении нового зарезервированного слова.
Открытие и закрытие дескриптора файла
open (FileVar, FileName);
close (FileVar);
Функция Open открывает указанный файл и ассоциирует с ним файловую переменную (дескриптор файла). В зависимости от спецсимвола, стоящего перед именем файла, файл можно открыть с разным способом доступа к нему.
open (FV,"FN");
Файл открыт для чтения. Запись в него запрещена.
open (FV,">FN");
Файл открыт для записи. Когда файл открыт таким способом, его содержимое автоматически стирается (а если файл не существует - создается) и в файл можно добавлять данные.
open (FV,">>FN");
Файл открыт для записи в конец. При таком способе открытия файла, тело файла не изменяется и разрешено добавлять строки в его конец.
open (FV,"+<FN");
Файл открыт для чтения и записи.
open (FV,"|FN");
Направить информацию на вход программы.
open (FV,"FN|");
Считать информацию с выхода программы.
open (FV,"|FN|");
И то и другое.
Из файла можно считать данные в виде массива и построчно. При считывании файла построчно, какой-то переменной, при первом считывании, присваивается первая строка файла и указатель перемещается на следующую строку. Такое присваивание возвращает True. При втором считывании присваивается вторая строка, при третьем - третья и т.д. до конца файла. Когда указатель дойдет до последней строки, счетчик сбрасывается, указатель перемещается на первую строчку файла, а возвращаемое выражение становится равным False
При считывании файла в массив, каждая строка файла помещается в отдельную ячейку массива. Плюсы и минусы этих методов очевидны: При считывании файла построчно, экономится память сервера, но работать с файлом становится неудобно, да и этот метод не очень производителен. Другое дело - работа с массивом: это быстро, это удобно, но есть очевидный минус - сильная загрузка памяти сервера. Но несмотря на это, данный метод пользуется огромной популярностью при написании небольших скриптов.
Чтобы считать файл/строку в какую-то переменную, этой переменной присваивают дескриптор файла, заключенный в треугольные скобки:
@array = <FileVar>;
$Var = <FileVar>;
Чтобы закрыть файл, используют функцию Close. Хотя её использование не обязательно, т.к. файл закроется сам после окончания выполнения скрипта, но желательно и является признаком хорошего стиля программирования.
Запись в тело файла
Нетрудно догадаться, что работать с файлом (считывать и записывать информацию) можно только тогда, когда он открыт.
Выводятся данные в файл всё тем же оператором Print. Оператору необходимо указать, в какой именно файл (может быть несколько одновременно открытых файлов) следует выводить информацию, затем помещают выражение, предназначенное для вывода:
open (file,">>file.txt");
print file "Здесь был Вася";
close file;
Если не указать файловую переменную, строка "Здесь был Вася" выведется на экран браузера.
Путь к файлу
Если опустить путь к файлу, а указать только его имя, будет считаться, что указанный файл лежит в той же директории, что и файл скрипта. Допускается указывать как абсолютный, так и относительный путь. К примеру, имеем такое дерево файлов и каталогов:
А относительно файла script.pl, пути будут такими:
MYDIR/file0.txt
file1.txt
../HTDOCS/file2.txt
При написании CGI программ принято использовать относительные пути, т.к. владельцы WEB-серверов часто скрывают абсолютное расположение своих директорий.
Блокировка файла, функция Flock
flock(FileVar, operation);
Сразу сделаю небольшую оговорочку, эта функция работает ТОЛЬКО под Unix-подобными операционными системами (Unix, Linux, FreeBSD, SunOS и др.) и Windows NT, W2k, XP...
Необходимость блокировки файлов возникает очень часто когда ваша Perl программа использует данные непосредственно из файлов. Это может быть гостевая книга, форум, чат, счетчик и т. д.
Сначала кажется, что никаких проблем не будет если просто написать код, открывающий файл при необходимости и закрывающий его, после завершения операции чтения/записи:
Если использовать такой код при создании, к примеру, гостевой книги, то существует вероятность, при которой один пользователь добавляет запись, а другой просматривает записи в одно и то же время. Таким образом одновременно два процесса в одно и то же время пытаются выполнить операцию ввода/вывода (в/в) с файлом. Это может привести к серьезным ошибкам, вплоть до потери данных. Для того, чтобы избежать таких ситуаций, необходимо блокировать файл непосредственно перед выполнением операции в/в. В Perl'e есть специальная функция для блокировки файлов, которая используют системные вызовы.
В качестве параметра operation допускаются следующие значения:
"LOCK_SH" или "1"
Блокировка для чтения
"LOCK_EX" или "2"
Блокировка для записи
"4"
"двухстороннее" блокирование
"LOCK_UN" или "8"
Разблокирование
Используя эту функцию, можно обезопасить свою программу от ошибки ввода/вывода. Код чтения данных из файла с использованием блокировки может выглядеть так:
Примечание: Не обязательно файл разблокировывать, т.к. при закрытии файловой переменной, Perl сделает это автоматически.
Код записи данных в файл, с блокировкой:
Есть одна особенность при использовании блокировки файлов: если к файлу может обратиться хотя бы один процесс, в котором не ставится блокировка, то вся система блокирования становится бесполезной. Другими словами, надо использовать блокировку не только при создании/обновлении/записи в нужный файл, но и в других скриптах, работающих с этими файлом.
* * * *
Напишем скрипт, который записывает в файл переданную ему строчку, и удаляет строку с переданным номером:
#!/usr/bin/perl
# programm 13
print "Content-type: text/html\n\n";
&parse_form;
print <
Добавить запись
Удалить запись номер:
END
; # вывели форму
if ($FORM{'action'} eq "add")
{ # выполняем этот блок когда хотим записать в файл
open(file,">>file.txt");
print file "$FORM{'string'}\n";
close file;
open(file,"file.txt");
@array=;
close file;
foreach $i(@array){
$u++;
print "$u. $i ";
}
}
elsif ($FORM{'action'} eq "del")
{ # выполняем этот блок когда хотим удалить строку
open(file,"file.txt");
@array=;
close file;
open(file,">file.txt");
$size=@array;
for($i=0;$i<=$size;$i++){
unless($i==$FORM{'number'}-1){
print file $array[$i]
}
}
close file;
open(file,"file.txt");
@array=;
close file;
foreach $i(@array){
$u++;
print "$u. $i ";
}
}
else
{ # вып. этот код когда хотим просмотреть все записи
open(file,"file.txt");
@array=;
close file;
foreach $i(@array){
$u++;
print "$u. $i ";
}
}
Возможно, Вам будет трудно поначалу разобраться с работой этой программы. Попробуйте мысленно "запустить" её, представив что Вы - это Perl. Последовательно интерпретируйте код, возможно записывая часть результатов на бумагу. Мысленно подставляйте значения в форму и снова "запускайте" её, тогда Вы быстро поймете работу программы. Важно обладать таким навыком, это впредь поможет Вам находить ошибки в своих и чужих скриптах.
* * * *
Может ли иметь одна программа дескриптор файла "ONE" и метку "ONE" ?
Если оператор Print не содержит указания записи в файл, но стоит сразу после оператора Open, сможет ли он записать в файл какую-либо строку?
Посмотрите на дерево каталогов, приведенное выше по тексту. Составьте путь к файлу file0.txt относительно file2.txt и наоборот.
Составьте абсолютный путь к файлу file.txt, если относительно файла script.pl его путь выгладет так: "/DOCS/file.txt"
Напишите программу, которая создает в директории с HTML документами, HTML файл, в котором записана таблица Пифагора. Откройте этот файл через его URL. Всё ли правильно отображается?