Создание серверных приложений на языке PERL

         

с этого урока мы будем


Урок 13. Функции работы с файлами

Собственно, начиная с этого урока мы будем изучать встроенные в 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;

Если не указать файловую переменную, строка "Здесь был Вася" выведется на экран браузера.

Путь к файлу

Если опустить путь к файлу, а указать только его имя, будет считаться, что указанный файл лежит в той же директории, что и файл скрипта. Допускается указывать как абсолютный, так и относительный путь. К примеру, имеем такое дерево файлов и каталогов:

D:/USR/LOCAL/APACHE |----> CGI-BIN | |----> MYDIR | | |----> file0.txt | | | |----> script.pl | |----> file1.txt | |----> HTDOCS |----> file2.txt



Тогда абсолютные пути к файлам будем иметь такими:

D:/USR/LOCAL/APACHE/CGI-BIN/MYDIR/file0.txt D:/USR/LOCAL/APACHE/CGI-BIN/file1.txt D:/USR/LOCAL/APACHE/CGI-BIN/script.pl D:/USR/LOCAL/APACHE/HTDOCS/file3.txt

А относительно файла 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 программа использует данные непосредственно из файлов. Это может быть гостевая книга, форум, чат, счетчик и т. д.

Сначала кажется, что никаких проблем не будет если просто написать код, открывающий файл при необходимости и закрывающий его, после завершения операции чтения/записи:

open(file, "file.txt"); while($string=<file>){ print $string; } close(file);

Если использовать такой код при создании, к примеру, гостевой книги, то существует вероятность, при которой один пользователь добавляет запись, а другой просматривает записи в одно и то же время. Таким образом одновременно два процесса в одно и то же время пытаются выполнить операцию ввода/вывода (в/в) с файлом. Это может привести к серьезным ошибкам, вплоть до потери данных. Для того, чтобы избежать таких ситуаций, необходимо блокировать файл непосредственно перед выполнением операции в/в. В Perl'e есть специальная функция для блокировки файлов, которая используют системные вызовы.

В качестве параметра operation допускаются следующие значения:

"LOCK_SH" или "1" Блокировка для чтения
"LOCK_EX" или "2" Блокировка для записи
"4" "двухстороннее" блокирование
"LOCK_UN" или "8" Разблокирование
<


Используя эту функцию, можно обезопасить свою программу от ошибки ввода/вывода. Код чтения данных из файла с использованием блокировки может выглядеть так:

open(file, "file.txt"); flock(file, LOCK_SH); while($string=<file>){ print $string; } close(file);

Примечание: Не обязательно файл разблокировывать, т.к. при закрытии файловой переменной, Perl сделает это автоматически.

Код записи данных в файл, с блокировкой:

open (FH, ">>data.tmp"); flock(FH, 2); $str="new line"; print FH $str; flock(FH, 8); close(FH);

Есть одна особенность при использовании блокировки файлов: если к файлу может обратиться хотя бы один процесс, в котором не ставится блокировка, то вся система блокирования становится бесполезной. Другими словами, надо использовать блокировку не только при создании/обновлении/записи в нужный файл, но и в других скриптах, работающих с этими файлом.

* * * *

Напишем скрипт, который записывает в файл переданную ему строчку, и удаляет строку с переданным номером:

#!/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; 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. Всё ли правильно отображается?

    Дополнительный материал: [работа с файлами]  [работа с файлами 2]  [работа с файлами 3]

    [Содержание]  [Вступление]  [необходимое для начала изучения]  [урок 1]  [урок 2]  [урок 3]  [урок 4]  [урок 5]  [урок 6]  [урок 7]  [урок 8]  [урок 9]  [урок 10]  [урок 11]  [урок 12]  [урок 13]  [урок 14]  [урок 15]  [урок 16]  [урок 17]  [урок 18]  [урок 19]  [урок 20]  [урок 21]  [урок 22]  [урок 23]  [урок 24]  [урок 25]  [урок 26]  [урок 27]  [урок 28]  [правила хорошего тона]  [приложение A]  [приложение Б]  [приложение В]  [заключение]  [благодарности] 



    Copyright (c) ClericICN, 2002

    Содержание раздела