Глава 12. Встроенные функции: работа с файлами

Коротко

В этой главе рассказывается о средствах работы с файлами Perl. Особое внимание уделяется функции, которые обычно работают с физическими(то есть расположенными на диске) файлами, их именами и каталогами. Это — очень важная и объемная тема; хотя полный обзор невозможен, данная глава дает неплохую базу, которая позволит читателю быть достаточно компетентным в данном вопросе. (Одна из причин внушительного объема этой темы — то, что многие функции дублируют друг друга. Девиз Perl «всегда есть несколько способов сделать что-либо» проявляет себя в области работы с файлами с особенной полнотой.)

Подсказка: Противники Unix должны сразу уяснить, что работа с файлами в Perl основывалась изначально именно на файловой системе этой операционной системы. Язык по-прежнему в значительной степени придерживается прежней структуры, поддерживая права доступа к файлам Unix, символические ссылки, и т. д. Чтобы проверить, какие именно функции поддердиваются в вашей операционной системе, потребуются некоторые эксперименты с конкретной версией Perl (особенно, когда дело дойдет до установки прав доступа к вашим файлам).

Кое-что о работе с файлами

Большинство программистов знакомо с принципами, на которых строится работа с файлами. Чтобы работать с данными, содержащимися в файле, программа «открывает» его, получая соответствующий дескриптор (file handle). Эта процедура создает поток ввода или вывода, и дальнейшие операции (чтение, запись файла) ссылаются на поток через дескриптор. По завершении работы, файл закрывается.

В этой главе этот процесс рассматривается более глубоко. Мы будем работать не только с дескрипторами, но и с функциями, которые управляют непосредственно файлами и каталогами, расположенными на диске. Кроме того, здесь рассказывается о создании и использовании баз данных DBM (Unix), так как этот материал популярен в среде программистов CGI-приложений.

Необходимо запомнить несколько соглашений. Во-первых, имена дескрипторов файлов в Perl, чтобы отличить их от зарезервированных идентификаторов, обычно набираются заглавными буквами. (Дескрипторы файлов не требуют разыменовывающего префикса типа $. Чтобы работать с ними как с переменными, — например, чтобы скопировать — надо обратиться к записи таблицы символом с тем же самым именем.)

Подсказка: Встречая имя (например, NAME), которое можно интерпретировать как дескриптор файла, Perl  обращается к записи таблицы символов *NAME и извлекает дескриптор файла. Поэтому если вы, например, выполните операцию присвоения *NEWNAME = *NAME для записей таблицы символов, то NEWNAME и NAME будут ссылаться на один и тот же дескриптор.

Во-вторых, надо помнить, что обращение к файлам наиболее часто приводят к ошибкам, — поэтому наиболее важные операции стоит сопровождать конструкцией «or die» или чем-то подобным. Наконец, учтите, что Unix использует косую черту (/) для разделения каталогов в полном пути к файлу. Если ваша операционная система (Windows или DOS) использует обратную косую черту (\), не забудьте, что для Perl в строках, ограниченных двойными кавычками, это специальный символ и его надо набирать с помощью escape-последовательности (\\):

open (FILEHANDLE, "tmp\\file.txt")

      or die ("Cannot open file.txt");

while (<FILEHANDLE>) {

   print;

}

Заметьте также, что, поскольку Perl так сильно ориентированя именно на файлы и работу с ними, материал, относящийся к данной главе, можно найти и в других разделах книги: в главе 4 — операторы работы с файлами типа -X, в главе 9 — специальные переменные (например, $/ — разделитель входных записей, $, — разделитель выходных записей, $| — буферизация вывода, и т. д.). Наконец, в главе 10 разбираются функции, упаковывающие данные в записи фиксированного размера, что удобно для файлов с прямым доступом к данным (функции pack, unpack и vec).

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

Непосредственные решения

open — открытие файл

Чтобы открыть файл, используется функцию open:

open дескриптор, выражение

open дескриптор

Эта функция открывает файл с заданным именем и создает указанный дескриптор файла. После ее вызова дескриптор может использоваться для ссылок на файл в самых разных операциях. Если имя не задано, Perl пытается открыть файл с именем, совпадающим с именем дескриптора.

Функция open возвращает ненулевое значение (соответствует условию истина), если файл успешно открыт, и неопределенное значение (соответствует условию ложь), если сделать этого не удалось. (Если в качестве файла открывается канал, то возвращаемое значение в случае успешного завершения работы функции — это идентификатор дочернего процесса.)

Имя файла может содержать дополнительные символы, указывающие, как именно следует открыть его:

  • Если имя имеет префикс < или не имеет префикса, файл открывается для чтения.

  • Если имя имеет префикс >, файл открывается для записи и полностью очищается (если он уже существует) или же создается новый файл.

  • Если имя имеет префикс >>, файл открывается для записи, а данные дописываются в его конец. Если файл не существует, создается новый.

  • Если имя имеет префикс +<, файл открывается для чтения и записи. Если файл существует, его содержимое сохраняется.

  • Если имя имеет префикс +>, файл открывается и для чтения и записи, однако, если он уже существует, то полностью очищается.

  • Если имя имеет префикс | или же перед ним стоит символ |, Perl рассматривает эту конструкцию как канал вывода, то есть как имя программы, которой на вход будут подаваться выводимые сценарием данные (подробнее см. главу 11).

  • Если имя имеет суффикс | или же после него стоит символ |, Perl рассматривает эту конструкцию как канал ввода, то есть как имя программы, вывод которой будет считываться сценарием в качестве данных (подробнее см. главу 11).

  • Если в качестве имени файла заданы конструкции |– или –|, порождается дочерний процесс, функция open возвращает его идентификатор , а операции ввода (–|) или вывода (|–) будут приводить к обмену информацией с дочерним процессом (подробнее см. главу 11).

  • Если в качестве имени файла задан дефис –, функция открывает стандартный поток ввода (обычно STDIN).

  • Если в качестве имени файла заданы символы >–, функция открывает стандартный поток вывода (обычно STDOUT).

  • Если выражение начинается с конструкции >&, то имя за ней интерпретируется либо как имя дескриптора файла Perl (если это текст), либо как дескриптор файла Unix (если это число).

    Подсказка: Можно использовать символ & также и после конструкций >>, +>, +>>, < и +<.

  • Если выражение начинается с конструкции <&=nn, где nn — это число, то Perl рассматривает nn как дескриптор файла и обрабатывает его как функция fdopen языка С.

    В следующем примере файл открывается для записи, и в него выводится некоторый текст:

    open (FILEHANDLE, ">hello.txt")

          or die ("Cannot open file hello.txt");

    print FILEHANDLE, "Hello!";

    close (FILEHANDLE);

    Hello!

    close — закрытие файла

    Функция close закрывает открытый файл или канал по окончании работы с ним. При этом в файл или канал пересылаются все данные, еще находящиеся в буфере вывода, а дескриптор файла деинициализируется, так что дальнейшие операции с ним (кроме открытия нового файла) становятся невозможны:

    close дескриптор

    close

    Если дескриптор файла опущен, функция закрывает поток, который установлен как STDOUT (см. описание функции select далее в этой главе).Она возвращает значение истина, если удалось вывести остаток буфера и успешно закрыть файл.

    Если закрывается канал, функция close ожидает завершения работы процесса, связанного с ним, чтобы можно проверить вывод через канал. (Код завершения программы, с которой происходил обмен данными, записывается в переменную Perl $?.)

    Пример использования функции close:

    open (FILEHANDLE, ">hello.txt")

          or die ("Cannot open file hello.txt");

    print FILEHANDLE, "Hello!";

    close (FILEHANDLE);

    Hello!

    print — вывод в файл

    Функция print неоднократно использовалась на протяжении всей книги, в том числе, в предыдущей главе. Она выводит список в файл, обозначенный дескриптором:

    print дескриптор, список

    print список

    print

    В следующем примере (он уже встречался в этой главе) функция print записывает информацию в файл:

    open (FILEHANDLE, ">hello.txt")

          or die ("Cannot open file hello.txt");

    print FILEHANDLE, "Hello!";

    close (FILEHANDLE);

    Hello!

    Функция возвращает значение истина при успешном завершении. Если не задан дескриптор, вывод производится в STDOUT или в дескриптор файла, установленный как STDOUT (см. описание функции select далее в этой главе). Если список опущен, используется переменная $_. Поскольку print работает со списками, в которых каждый элемент данных считается отдельной записью, можно выводить в файл списки следующим образом (обратите внимание, что здесь переопределяется разделитель выходных записей, хранимый в переменной $,):

    open (FILEHANDLE, ">array.dat")

          or die ("Cannot open file array.dat");

    $, = "\n";

    $array = (1, 2, 3);

    print FILEHANDLE, @array;

    close (FILEHANDLE);

    Теперь содержимое файла array.dat представляет собой:

    1

    2

    3

    Следующий код открывает только что записанный файл (обратите внимание, что в массив @array считываются сразу все строки файла и удаляется символ новой строки):

    open (FILEHANDLE, "<array.dat")

          or die ("Cannot open file array.dat");

    chomp(@array = <FILEHANDLE>);

    close FILEHANDLE;

    print join (’, ’ @array);

    1, 2, 3

    write — запись в файл

    Вместо print для записи в файл можно использовать функцию write:

    write дескриптор

    write выражение

    write

    Мы уже встречались с этой функцией в предыдущей главе (см. дополнительные подробности в гл. 11). write используется для вывода форматированных записей, а не как функция вывода общего назначения (для этой цели используется print). Если указан дескриптор файла, write выводит очередную форматированную запись для формата, приписанного этому дескриптору. Если указано выражение, то оно должно быть текстовой строкой, интерпретируемой как имя дескриптора. Наконец, если write вызывается без параметров, то используется STDOUT или дескриптор, который установлен как STDOUT (см. описание функции select далее в этой главе).

    В следующем примере форматированную запись в файл format.txt выводится форматированная запись:

    open (FILEHANDLE, ">format.txt")

          or die ("Cannot open file format.txt");

    format FILEHANDLE =

    @<<<<<<<<<<<@>>>>>>>>>>>>>>>

    $text1,     $text2

    .

    $text1 = "Hello";

    $text2 = "there";

    write FILEHANDLE;

    close (FILEHANDLE);

    Hello                 there!

    binmode — установка двоичного режима

    Некоторые операционные системы (например, DOS и Windows) различают текстовые и двоичные файлы (точнее, режимы работы с файлами). При выводе символов новой строки \n автоматически заменяется парой CR+LF (\r\n), а при вводе \r\n заменяется символом новой строки \n. Чтобы при выводе использовать только символы \n, используется функция binmode:

    binmode дескриптор

    Рассмотрим пример использования Perl в MS DOS. При выводе строки, завершающейся символом \n в выходном файле появится \r\n (ASCII-коды 0x0d0x0a):

    open (FILEHANDLE, ">data.txt")

          or die ("Cannot open file data.txt");

    print FILEHANDLE "Hello\nthere!\n";

    close (FILEHANDLE);

    C:\debug data.txt

    -d

    107A:0100   48 65 6C 6C 6F 0D 0A 74-68 65 72 65 21 0D 0A

    Hello..there!...

    (Для просмотра файла в шестнадцатеричном режиме в данном случае использовался отладчик MS DOS, хотя другие программы, например, Norton Commander гораздо удобнее.)

    Если же вызвать функцию binmode, то в файл попадут только символы новой строки:

    open (FILEHANDLE, ">data.txt")

          or die ("Cannot open file data.txt");

    binmode FILEHANDLE;

    print FILEHANDLE "Hello\nthere!\n";

    close (FILEHANDLE);

    C:\debug data.txt

    -d

    107A:0100   48 65 6C 6C 6F 0A 74-68 65 72 65 21 0A

    Hello.there!...

    Управление буферизацией вывода

    Можно заставить Perl сбрасывать на диск (или другой носитель) буфер вывода после каждой операции print или write. Для этого переменной Perl $| надо присвоить ненулевое значение:

    $| = 1;

    (В противном случае все, что направляется в поток вывода, накапливается в буфере (области памяти) и записывается только после заполнения буфера или закрытия потока.) Того же результата можно добиться, если вызвать функцию autoflush:

    autoflush дескриптор выражение

    Чтение файлов, переданных через командную строку

    Имена файлов, стоящие после имени сценария в командной строке, передаются коду в качестве потока ввода:

    % printem file1.txt file2.txt

    Если после этой команды обратиться к STDIN, то вместо ввода с консоли (клавиатуры) мы получим объедиенное содержимое файлов file1.txt и file2.txt:

    while (<>) {

       print;

    }

    Here is

    a

    file!

    Here is 

    another

    file!

    Чтение из дескриптора файла

    Выражение вида <дескриптор> возвращает следующую строчку, считанную из файла. Это полезно, когда надо прочитать открытый файл. Например, следующий фрагмент кода читает весь текст из файла file.txt:

    open (FILEHANDLE, "<file.txt")

          or die ("Cannot open file file.txt");

    while (<FILEHANDLE>) {

       print;

    }

    Here

    is

    a

    file!

    Если дескриптор файла не указан, используется STDIN.

    read — чтение входных данных

    Функция read читает данные из дескриптора файла:

    read дескриптор, скаляр, длина, смещение

    read дескриптор, скаляр, длина

    (Обратите внимание: функция read не является парной для функции write!)

    Эта функция пытается прочитать из дескриптора файлов число байтов, указанное параметром длина, и записать их в скалярную переменную.

    Параметр смещение (если он задан) указывает, с какой позиции от начала скаляра (строки) надо размещать считанные байты. Если он не задан или равен нулю, то скалярной переменной присваивается значение-строка, считанная из файла, а прежнее содержимое переменной теряется. Если же задано смещение, то текущим значением скалярной переменной должна быть текстовая строка, от которой берется несколько первых байтов, к ним добавляются байты, считанные из файла, и все запоминается в качестве нового значения переменной. Поэтому длина строки может уменьшиться или увеличиться. Если текущее значение скаляра не является текстовой строкой, оно преобразуется к формату текстовой строки, — например, число 123.45 в строку "123.45". Если текущая длина строки меньше указанного смещения, она дополняется двоичными нулями. (Для экспериментальной проверки полезно воспользоваться функцией vec из главы 10.)

    Функция read возвращает количество успешно считанных байт. Значение ноль указывает на конец файла. Значение undef говорит о том, что в процессе чтения были ошибки.

    Пример (чтение файла байт за байтом с последующим выводом):

    open (FILEHANDLE, "<file.txt")

          or die ("Cannot open file file.txt");

    $text = "";

    while (read (FILAHANDLE, $newtext, 1)) {

       $text .= $newtext;

    }

    print $text;

    Here

    is

    a

    file!

    readline — считывание строки ввода

    Функция readline читает из файла одну строку (в скалярном контексте) или список строк до конца файла (в списковом контексте) и возвращает результат. Для идентификации файла ей передается выражение, которое должно быть записью таблицы символов (typeglob) с тем же именем, что и дескриптор файла (например, readline (*STDIN);):

    readline выражение

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

    Чтобы определить конец строки, функция readline использует переменную Пела $/. В следующем примере из STDIN считывается строка и выводится на экране:

    $input = readline (*STDIN);

    print $input;

    Here is a line of text.

    getc — считывание одиночного символа

    Функция getc возвращает одиночный символ, полученный из дескриптора файла. Если последний опущен, используется STDIN:

    getc дескриптор-файла

    getc

    Функция возвращает символ или неопределенное значение по достижении конца файла. Функция getc уже использовалась в предыдущей главе. В следующем примере с ее помощью файл читается побайтно (однако, это не означает, что ввод не буферизуется — подробнее см. гл. 11):

    open (FILEHANDLE, "<file.txt")

          or die ("Cannot open file file.txt");

    while ($char = getc FILEHANDLE) {

       print $char;

    }

    Here

    is

    a

    file!

    seek — поиск заданной позиции в файле

    Функция seek используется для установки текущей позиции в файле в точку, с которой начнется следующая операция ввода или вывода:

    seek дескриптор, позиция, как-считать

    В качестве текущей позиции дескриптора файла устанавливается заданная пользователем позиция. Параметр позиция задается в байтах, а параметр как-считать указывает, как его интерпретировать. Возможные значения:

  • 0 — установить текущую позицию в значение позиция (отсчитываемое от начала файла)

  • 1 — сдвинуть текущую позицию на указанное количество байтов (с начала или с конца файла в зависимости от знака позиции)

  • 2 — установить текущую позицию в значение позиция, отсчитываемое от конца файла (значение параметра позиция должно быть отрицательным или нулевым)

    Обратите внимание, что параметр как-считать обязателен.

    Рассмотрим пример. Файл file.txt содержит текст:

    This is the text.

    С помощью следующей команды текущая позиция устанавливается на начало слова «text», а затем, начиная с этой позиции, выполняется операция чтения:

    open (FILEHANDLE, "<file.txt")

          or die ("Cannot open file file.txt");

    seek FILEHANDLE, 12, 0;

    while (<FILEHANDLE>) {

       print;

    }

    close (FILEHANDLE);

    text.

    Функция seek часто используется с файлами, разбитыми на записи фиксированного размера. С ее помощью легко получить доступ к любой записи в файле (такой доступ называется прямым (random), в отличие от последовательного (sequential access), который требует считывать все промежуточные записи, прежде чем вы доберетесь до нужного места). Чтобы обслуживать записи постоянной длины (так как переменные Perl — обычно объекты переменной длины), можно использовать функции Perl pack, unpack, vec и ряд других.

    tell — текущая позиция в файле

    Функция tell возвращает значение текущей позиции в файле, отсчитываемое в байтах от начала файла:

    tell дескриптор

    tell

    Если параметр дескриптор опущен, tell использует последний прочитанный файл. В следующем примере с помощью функции seek устанавливается позиция в файле, а затем tell сообщает ее значение:

    open (FILEHANDLE, "<file.txt")

          or die ("Cannot open file file.txt");

    seek FILEHANDLE, 12, 0;

    print tell FILEHANDLE;

    close (FILEHANDLE);

    12

    Подсказка: С помощью функции tell можно узнать размер файла, установив текущую позицию на конец файла:

    seek FILEHANDLE, 0, 2; 

    $size_of_file = tell FILEHANDLE;

    stat — информация о файле

    Функция stat возвращает список из тринадцати элементов, описывающих состояние файла:

    stat дескриптор

    stat выражение

    stat

    Файл задается с помощью дескриптора файла или текстовой строки, соответствующей его имени. Если аргумент stat не задан, используется переменная $_. Элементы, описывающие состояние файла, представляют собой следующие значения:

  • 0 (dev) — номер файловой системы

  • 1 (ino) — индексный дескриптор (характеристики файла в операционной системы Unix)

  • 2 (mode) — режимы доступа файла (разрешена запись, разрешено чтение, исполняемый файл, каталог, и т. д.)

  • 3 (nlink) — число жестких ссылок на файл в файловой системе

  • 4 (uid) — идентификатор пользователя (User ID) для владельца файла

  • 5 (gid) — идентификатор группы пользователя (Group ID) для владельца файла

  • 6 (rdev) — идентификатор устройства для специальных файлов

  • 7 (size) — полный размер файла в байтах

  • 8 (atime) — время последнего обращения к файлу

  • 9 (mtime) — время последнего изменения файла

  • 10 (ctime) — время последнего изменения индексного дескриптора

  • 11 (blksze) —размер блока по умолчанию для стандартной системы ввода/вывода

  • 12 (blocks) — число блоков, отведенных для файла

    Подсказка: Время отсчитывается в секундах «от начала эпохи», то есть от 1 января 1970 года (это справедливо почти для всех операционных систем, не только для Unix, за исключением, например, MacOs). Кроме того, не все элементы состояния поддерживаются другими операционными системами.

    В следующем примере с помощью функции stat выводится размер файла:

    $filename = "file.txt";

    ($dev, $ino, $nlink, $uid, $gid, $rdev, $size, $atime, 

     $mtime, $ctime, $blksize, $blocks) = stat ($filename);

    print "$filename is $size bytes long.";

    file.txt is 20 bytes long.

    Если в качестве дескриптора файла функции stat задан символ подчеркивания, она возвращает список значений, соответствующих последней проверке файла с помощью функции stat или операторов проверка файла (см. раздел «Операторы проверки файлов» главы 4).

    Файловые функции модуля POSIX

    Лаборатория компьютерных систем Национального института стандартов и технологий (the National Institute of Standards and Technology Computer Systems Laboratory — NIST/CSL) в содружестве с другими организациями создала стандарт POSIX — Portable Operating System Interface. Это обширная библиотека стандартизированных С-подобных функций, покрывающих стандартные потребности программирования, от базовых математических вычислений до продвинутой работы с файлами.

    Модуль Perl POSIX предоставляет доступ практически ко всем стандартным функциям POSIX версии 1003.1 — всего около 250. Они не являются встроенными, подобно остальным функциям этой главы, однако упоминаются здесь, так как модуль POSIX обеспечивает б’ольше возможностей, чем встроенные функции Perl. Модуль POSIX подключается командой use:

    use POSIX;      # добавить всю библиотеку POSIX

    use POSIX qw/функция/  # добавить одну функцию

    (Использование во втором варианте псевдокавычек qw/.../ (см. таблицу 2.3 в главе 2) — самый простой способ создать список из строк-имен функций, заключенных в кавычки. Более подробно о use рассказывается в главе 13.)

    Например, в следующем фрагменте функция fstat модуля POSIX позволяет получать информацию о состоянии файла и вывести его размер (обратите внимание, что функция fstat использует дескрипторы, а не имена файлов):

    use POSIX;

    $filename = "file.txt";

    $descrip = POSIX::open($filename, POSIX::O_RDONLY);

    ($dev, $ino, $nlink, $uid, $gid, $rdev, $size, $atime, 

     $mtime, $ctime, $blksize,

     $blocks) = POSIX::fstat ($descrip);

    print "$filename is $size bytes long.";

    file.txt is 7 bytes long.

    select — выбор дескриптора файла для STDOUT

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

    select дескриптор

    select

    Первая форма устанавливает заданный дескриптор файла в качестве потока вывода, который будет использоваться затем по умолчанию. Вторая позволяет получить текущий дескриптор файла по умолчанию для операций вывода.

    В следующем примере с помощью перенаправления стандартный поток вывода STDOUT переадресуется в новый файл, а функция print, заданная без явного указания дескриптора файла, выводит даные в этот файл:

    open (FILEHANDLE, ">hello.txt")

          or die ("Cannot open file hello.txt");

    select FILEHANDLE;

    print "Hello!";

    close (FILEHANDLE);

    eof — проверка конца файла

    Функция eof позволяет проверить при чтении данных, не достигнут ли уже конец файла:

    eof дескриптор

    eof ()

    eof

    Эта функция возвращает значение истина (число 1), если вы находитесь в конце файла, заданного через дескриптор — точнее, если следующая операция чтения приведет к ситуации «конец файла». (Значение 1 возвращается и в том случае, если дескриптор файла не открыт.) Без аргумента функция eof использует последний прочитанный файл. Поведение функции в том случае, когда ее аргумент — пустая пара круглых скобок, рассматривается ниже.

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

    open (FILEHANDLE, "<file.txt")

          or die ("Cannot open file file.txt");

    $text = "";

    until (eof(FILEHANDLE) {

       read (FILEHANDLE, $newtext, 1);

       $text .= $newtext;

    }

    print $text;

    Here

    is

    a

    file!

    Функция eof с пустой парой круглых скобок в качестве аргумента используется  при чтении потока ввода STDIN, в качестве которого используются несколько заданных в командной строке файлов. В следующем примере ввыводится содержимое первого файла с текстом «Here is the text!», второго с фразой «Here is another text!», а затем выводится строка «And that is it!». Сценарий запускается так:

    %perl -w printit.pl file1.txt file2.txt

    Вот код сценария:

    while (<>) {

       print;

       if (eof()) {

          print "And that is it!";

       }

    }

    Here is the text!

    Here is another text!

    And that is it!

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

    while (<>) {

       print;

       if (eof) {

          print "-" x 30;

       }

       if (eof()) {

          print "And that is it!";

       }

    }

    Here is the text!

    --------------------

    Here is another text!

    --------------------

    And that is it!

    Обратите внимание, что конструкция while (<>) позволяет прочитать до конца весь поток ввода, несмотря на то, что он состоит из двух физических файлов. Команда <> возвращает неопределенное значение, если не может выполнить операцию чтения данных. Функция eof возвращает значение ложь, когда следом за текущей позицией ввода данных находится конец файла.

    Напоследок отметим, что функция eof используется сравнительно редка, так как функции Perl, предназначенные для работы с файлами, прекрасно сопрягаются с условными операторами и операторами цикла, — а именно, они возвращают значение ложь, когда возникает ошибка или когда в файле не остается данных для чтения.

    Запись базы данных DBM

    Операционная система Unix поддерживает очень простой в использовании формат баз данных DBM. В старых версиях Perl для работы с DBM преднозначались функции типа dbmopen и dbmclose. Однако теперь их вытеснила функция tie (с ней мы познакомимся, когда будем изучать объектно-ориентированное программирование в Perl):

    tie переменная, имя-класса, список-параметров

    Она связывает хеш и хранящуюся на диске базу данных DBM. В следующем примере хеш %hash связывается с файлом data.db (расширение .db соответствует базам данных DBM и добавляется автоматически при связывании переменной и файла<$FЭто утверждение автора не вполне истинно и остается целиком на его совести. DBM — это скорее способ хранения данных, а не формат файла — конкретный тип DBM (BD, GDBM, NDBM, SDBM) зависит от версии UNIX. В частности, под базы данных SDBM создается два файла, причем один получает расширение pag, а другой — dir, а файл базы данных GDBM вообще не получает расширения, если его не указать. — Примеч. ред.>), в хеш заносится новое значение и в результате мы получаем базу данных с нужной нам информацией:

    use Fcntl;

    use NDBM_File;

    tie %hash, "NDBM_File", ’data’,

               O_RDWR|O_CREAT|O_EXCL, 0644;

    $hash{drink} = ’root beer’;

    untie %hash;

    (Мы подключили модуль Fcntl, чтобы использовать символические константы типа O_RDWR, O_CREAT, и т. д.. Мистическое число 0644 соотвествует разрешениям на доступ файла — более подробно об этом рассказывается далее при описании функции chmod.)

    Как прочесть содержимое созданной базы данных, рассказывается в следующем разделе.

    Подсказка: Базы данных формата DBM поддерживаются не только операционной системой Unix но и, например, Win32. Просто используйте вместо NDBM_File модуль (и класс) SDBM_File<$FЧестно говоря, здесь автор выбрал не самый лучший пример — надежнее было бы использовать формат DB (Berkley DB), который реализован для всех платформ, а также позволяет создавать наиболее быстрые и компактные базы данных. Кроме того, необходимо предупредить, что хеш массивов или хеш хешей в DBM сохранить не удастся (хотя некоторые пользователи пытаются это сделать) — для этой цели следует использовать модуль MLDBM. — Примеч. ред.>.

    Как прочитать файл базы данных формата DBM

    Чтобы прочитать созданную в предыдущем разделе базу данных data.db, надо связать этот файл и хеш Perl и вывести данные из хеша:

    use Fcntl;

    use NDBM_File;

    tie %hash, "NDBM_File", ’data’, O_RDWR, 0644;

    print $hash{drink};

    untie %hash;

    root beer

    Чтобы работать с базами данных DBM этих сведений достаточно. Свяжите базу данных с переменной Perl (хешем), и хеш можно будет использовать как базу данных. (Тем не менее, детальное знакомство с классами и методами из модуля NDBM_File и/или SDBM_File вряд ли окажется лишним, хотя, например, использование DB_File является, как правило, наиболее надежным, устойчивым и рекомендуемым подходом.) Конечно, можно использовать и гораздо более мощные базы данных с возможностями, далеко превосходящими DBM. Однако если ваши запросы не слишком велики, базы данных DBM.

    Подсказка: Базы данных формата DBM поддерживаются не только под операционной системой Unix но и, например, под Win32. Просто используйте вместо NDBM_File модуль (и класс) SDBM_File.

    flock — блокировка файла

    Функция flock позволяет «заблокировать» файла, заданный дескриптором, для доступа со стороны других процессов:

    flock дескриптор, код-операции

    Эта операция управляет режимом доступа к файлу со стороны других процессов и, в частности, позволяет избежать конфликтов с другими программами, читающими файл, пока в него записываются новые данные. Хотя в системе Unix блокировка лишь рекомендуемая операция, для других операционных систем (например, для Windows NT) она обязательна. Следующие значения являются допустимыми для кода операции (чтобы использовать символические имена, надо подключить модуль Fcntl с помощью команды use Fcntl):

  • LOCK_SH (=1) — разделяемый доступ к файлу

  • LOCK_EX (=2) — монопольный доступ к файлу

  • LOCK_NB (=4) — совместно с LOCK_SH или LOCK_EX обеспечивает «быстрый возврат» — то есть функция flock возвращает управление в точку вызова, не дожидаясь, пока режим доступа к файлу активизируется (например, придется подождать разделяемого доступа, если какой-то процесс уже захватил монопольный доступ к файлу)

    ·       <![endif]>LOCK_UN (=8) — снимает режим блокировки, (то есть после выполнения этой операции процесс теряет все свои права на доступ к файлу).

    Разрешается комбинировать несколько (не конфликтующих) режимов с помощью операции «побитное или» (|).

    chmod — изменение прав доступа к файлу

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

    chmod список-параметров

    Первым элементом списка должно быть число, задающее права доступа, как это принято в операционной системе Unix (это число удобно задавать в восьмеричном представлении, — например, 0644 или 0600). Остальными элементами списка являются имена файлов. Функция возвращает число файлов, для которых операция была успешной.

    В следующем примере используется файл file.txt. Текущие права доступа к нему установлены в 0600. А именно, для этого файла команда Unix ls -l выводит результат:

    -rw-------   1 user       1 Oct 28 11:51 file/txt

    С помощью функции chmod можно изменить права доступа на 0644:

    chmod 0644, ’file.txt’;

    -rw-r--r--   1 user       1 Oct 28 11:51 file/txt

    Возможно, ваша операционная система не поддерживает восьмеричные коды прав доступа. Например, Windows поддерживает только три атрибута файлов: A (архивный), R (только для чтения), H (скрытый) и S (системный). Эти атрибуты изменяются с помощью команды MS DOS attrib или, в случае интерпретатора ActiveState Perl for Win32, функцийWin32::File::GetAttributes и Win32::File::SetAttributes.

    rename — переименование файлов

    Функция rename позволяет изменять имена файлов:

    rename старое-имя, новое-имя

    Она возвращает истину (число 1), если файл удалось переименовать, и ложь (число 0) в противном случае.

    glob — поиск файлов по шаблону

    Функция glob возвращает список файлов, имена которых соответствуют указанному шаблону («шаблон» следует понимать в смысле файловой системы Unix, а не как регулярное выражение Perl<$Fхотя в данном случае это почти одно и то же — регулярные выражения в Unix используются на уровне стандартных средств OC. — Примеч. ред.> ). Имя функции происходит от соответствующей команды Unix, хотя с не меньшим успехом эта функция Perl работает и для других операционных систем<$FК сожалению, эта наивная вера автора не выдерживает проверки практикой J. Использовать данную функцию обычно не рекомендуется даже в Unix, если используется оболочка C shell, а в Windows или DOS она может дать ошибочные результаты, если только не принять специальные меры. — Примеч. ред.>. Если не указан аргумент, используется переменная $_:

    glob выражение

    glob

    Например, следующий код выводит полный список файлов текущего каталога:

    print join("\n", glob (’*’));

    Подсказка: Можно вывести имена файлов следующим образом:

    while (<*.txt>) {

       print;

    }

    Дело в том, что Perl неявно вызывает функциюglob и превращает шаблон, указанного вместо дескриптора файла, в квазифайл, который состоит из строк, возвращаемых функцией glob. Однако для того, чтобы понять, как работает этот трюк, придется довольно глубоко залезть в документацию Perl.

    unlink — удаление файлов

    Функция unlink (название происходит от одноименной команды Unix, которую эта функция имитирует) позволяет удалять файлы, указанные в качестве ее аргумента. Функция возвращает число удаленных файлов. Если аргумент опущен, используется переменная $_:

    unlink список-файлов

    unlink

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

    print ’Deleted ’, unlink (<*.old>), ’ files.’;

    Deleted 98 files.

    Функция unlink не предназначена для удаления каталогов. Для этой цели следует использовать rmdir (см. ниже). Хотя при особых условиях функция unlink и способна удалять каталоги (см. документацию Perl), это может оказаться опасным для файловой системы.

    opendir — открытие каталога

    Функция opendir открывает каталог и создает дескриптор, который используется описываемыми ниже функциями readdir, telldir, seekdir, rewinddir и closedir:

    opendir дескриптор, выражение

    Каталог рассматривается как квазифайл, в котором записями служат имена файлов и подкаталогов. Пользователь может «считывать» их подобно строкам обычного файла, а также устанавливать позицию начала чтения с помощью перечисленных выше функций. Дескриптор файла, инициализированный функцией opendir как каталог, не может использоваться функциями файлового ввода/вывода, пока вы не закроете его функцией closedir и не откроете как обычный файл функцией open. Функция возвращает значение истина, если каталог удалось открыть, и ложь в противном случае.

    closedir — закрытие каталога

    Функция closedir закрывает каталог, ранее открытый с помощью функции opendir:

    closedir дескриптор

    Функция возвращает значение истина, если ее работа завершилась успехом, и ложь в противном случае.

    readdir — чтение содержимого каталога

    Функция readdir позволяет получить список файлов и подкаталогов в каталоге, ранее открытом с помощью opendir:

    readdir дескриптор

    По умолчанию имена файлов и подкаталогов начинают выводиться с первого содержащегося в каталоге имени, однако с помощью функций seekdir и rewinddir (см. далее) можно изменить порядок вывода. В списковом контексте readdir возвращает список из всех имен файлов, начиная с текущей позиции и до конца каталога. В скалярном контексте она возвращает очередное имя файла. Если список имен исчерпан, возвращается пустой список в списковом контексте и неопределенное значение в скалярном контексте.

    Подсказка: Если вы собираетесь не просто вывести полученный список файлов, а еще и проверить их состояние, то сперва посмотрите описание функции readdir, в документации Perl, — здесь есть подводные камни, о которых полезно знать.

    В следующем примере выводится список имен файлов, содержащихся в текущем каталоге:

    opendir (DIRECTORY, ".")

       or die "Cannot open current directory.";

    print join("/", readdir(DIRECTORY));

    closedir DIRECTORY;

    ./../T6.pl/Z.PL/P.PL/V.PL/W.PL

    seakdir — установка текущей позиции в каталоге

    Функция seakdir позволяет изменять текущую позицию в каталоге, открытом с помощью функции opendir:

    seekdir дескриптор, позиция

    Значение параметра позиция должно быть значением, возвращаемым функцией telldir (см. ниже).

    telldir — чтение текущей позиции в каталоге

    Функция telldir возвращает текущую позицию в каталоге, открытом с помощью opendir (с этой позиции будет начинаться очередная операция чтения, выполняемая функцией readdir):

    telldir дескриптор

    rewinddir — установка текущей позиции на начало каталога

    Функция rewinddir устанавливает позицию, используемую функцией readdir, на начало каталога:

    rewinddir дескриптор

    chdir — смена текущего каталога

    Вы можете изменить текущий каталог с помощью функции chdir:

    chdir выражение

    chdir

    Функция chdir изменяет текущий каталог на значение аргумента (текстовой строкой), если это возможно. Если не указан параметр, то текущим становится домашний каталог. Функция возвращает значение истина, если ее работа завершилась успехом, и ложь в противном случае.

    В следующем примере текущий каталог изменяется на родительский (обозначаемое как «..» как в DOS, так и в Unix), и выводится список файлов, хранящихся в нем:

    chdir "..";

    opendir (DIRECTORY, ".")

       or die "Cannot open directory.";

    print join (", ", readdir(DIRECTORY));

    closedir DIRECTORY;

    ., .., mail, .alias, .cshrc, .login, .plan, .profile

    mkdir — создание нового каталога

    Фунция mkdir создает новый каталог:

    mkdir выражение, права-доступа

    Новый каталог создается с именем, указанным первым аргументом (текстовой строкой), если это возможно. Второй параметр задает права доступа к каталогу в виде восьмеричного числа (для файловой системы Unix, см. выше описание функции chmod). Функция возвращает значение истина, если ее работа завершилась успехом, и ложь в противном случае.

    В следующем примере мы создаем новое каталог tmp, переходим в него и записываем файл:

    mkdir "tmp", 0744;

    chdir "tmp";

    open (FILEHANDLE, ">hello.txt")

       or die "Cannot open file hello.txt.";

    print FILEHANDLE "Hello!";

    close (FILEHANDLE);

    Подсказка: Версия Perl for Win32 игнорирует второй параметр, так что вы можете без проблем создавать каталоги, работая в Windows.

    rmdir — удалить каталог

    Функция rmdir удаляет каталог:

    rmdir выражение

    rmdir

    Разрешается  удалять только пустой каталог. Если не задано имя каталога, используется переменная $_. Функция возвращает значение истина, если ее работа завершилась успехом, и ложь в противном случае (в последнем случае в переменную $! помещается сообщение об ошибке).