Поиск

Открытие файлов

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

Из материала прошлых занятий вы уже знакомы с одним из дескрипторов — STDIN. Этот дескриптор автоматически передается программе при запуске и обычно связан с клавиатурой (позднее вы узнаете еще некоторые особенности дескриптора STDIN).

Формат имен дескрипторов тот же, что и имен других переменных Perl. Подробнее об этом шла речь на 2-м занятии, "Строительные блоки Perl: числа и строки". Единственное отличие — в именах дескрипторов файлов не должно быть символов, идентифицирующих тип переменной ($, @ или какого-нибудь другого). Поэтому рекомендуется в именах дескрипторов использовать только символы верхнего регистра, чтобы они случайно не совпали с современными или будущими зарезервированными служебными словами Perl, такими как foreach, else, if и т.д.

Для имени дескриптора можно использовать строковой скаляр или функцию, возвращающую строку. Такие дескрипторы файлов называются косвенными. Сведения об их использовании обычно не приводятся в учебных пособиях для начинающих. За дополнительной информацией о косвенных дескрипторах файлов обращайтесь к документации: страница perlfunc, раздел open.

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

open (дескриптор_файла, путь)

Первый аргумент функции open — дескриптор файла, второй аргумент — путь. Путь указывает, какой файл необходимо открыть, поэтому, если не указан полный путь, например с:/windows/system/, функция open попытается открыть файл в текущем каталоге. При успешном выполнении функция open возвращает ненулевое значение (Истина), при неудачном — возвращается undef (Ложь), например:

Здесь при удачном завершении функция open возвращает истинное значение, открывается дескриптор файла MYFILE и выполняется блок if. В противном случае файл не открывается, выполняется блок кода else, сообщающий об ошибке. Во многих программах Perl подобный синтаксис "открыть или сообщить об ошибке" может быть реализован с помощью функции die. Функция die останавливает выполнение программы и выводит сообщение об ошибке:

Died at имя_сценария line xxx

Здесь имя_сценария — название программы на Perl, xxx номер строки, в которой встретилась функция die. Функции die и open часто используются вместе следующим образом:

open(MYTEXT, "novel.txt") || die;

Программа или открывает файл, или прекращает свое выполнение. Если open завершилась неудачно, возвратив ложное значение, вступает в действие логический оператор ИЛИ (| |). В результате будет вычисляться аргумент, находящийся в правой части оператора (в данном случае — функция die). При удачном выполнении функции open правая часть логического выражения не вычисляется. Иногда используют другой вид логического ИЛИ — or.

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

close(HYTEXT);

Если попытаться открыть файл, указав в качестве параметров функции open один из уже открытых дескрипторов, то вначале этот дескриптор закрывается, а затем повторно открывается.

Пути

До сих пор мы открывали файлы, указывая только их имена, например novel.txt. При открытии файлов без указания имени каталога Perl считает, что файл находится в текущем каталоге. Чтобы открыть файл в другом каталоге, необходимо указать путь. Путь указывает операционной системе, где находится файл.

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

В системах Windows и MS-DOS в качестве разделителей в путях можно использовать символы обратной косой черты, например \Windows\users\pierse\novel.txt. Только при этом нужно помнить, что в строках, заключенных в двойные кавычки, символ обратной косой черты означает, что следующий за ним символ является специальным. Например:

Этот пример не сработает, потому что \п в строках в двойных кавычках обозначает символ перевода строки, а не букву л, а все остальные обратные косые черты будут просто игнорироваться Perl. Вот корректный способ открыть файл:

Чтобы эта же строка выглядела красивее, используйте символ косой черты (/) как разделитель путей в Windows и MS-DOS (в Windows и MS-DOS это допускается):

Пути могут быть как абсолютными (/home/foo в UNIX или c:/windows/win.ini в Windows), так и относительными (../junkfile в UNIX или ../bobdir/bobsfile.txt в Windows). Функция open в Windows способна воспринимать пути, следующие соглашению об универсальных именах UNC (Universal Naming Convention). Формат путей в UNC выглядит так:

\имя_машивы\ имя_ресурса

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

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

Береженого Бог бережет

Создание программ для компьютера часто сопровождается неоправданным оптимизмом у программистов. Они думают: "Вот теперь она работает как надо!" или "Все ошибки наконец-то исправлены". Вообще чувство гордости за проделанную работу — отличная вещь; все достижения принадлежат людям, которые пытаются сделать невозможное возможным. Но иногда самоуважение переходит все границы и превращается в самоуверенность или высокомерие. В одной из древнегреческих трагедий высокомерие всегда жестоко наказывалось богами.

Описанный феномен стал проявляться по мере распространения компьютеров. Фредерик П. Брукс (Frederic P. Brooks) в своей классической работе The Mythical Man-Month {Addison Wesley, 1975, с. 14) писал: "Все программисты — неисправимые оптимисты. Возможно, современное волшебство (программирование) особенно привлекает тех, кто верит, что все сказки имеют хороший конец, но... Все наши идеи ложны, нам свойственно ошибаться, поэтому наш оп-тимизм неоправдан".

До настоящего времени все приведенные примеры и упражнения имели дело с внутренними данными программы (множители чисел, массивы данных и т.д.) или с простыми строками, введенными пользователем с клавиатуры. При работе с файлами программы часто имеют дело с неподконтрольными им данными. Особенно это актуально, если данные не расположены на вашем компьютере, а пересылаются по сети. Поэтому следует иметь в виду, что может произойти сбой, на который программа должна отреагировать должным образом. Написание подобных программ называется безопасным программированием. "Безопасная" программа имеет бесспорные преимущества перед обычной, особенно если это касается устойчивости работы.

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

Умирать, так с музыкой

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

Функции die может передаваться список аргументов, которые будут выводиться вместо стандартного сообщения. ' Если сообщение не содержит символа перевода строки, то в его конец добавляется текст at имя_сценария line xxx, например:

В Perl предусмотрена специальная переменная $!, содержащая сообщение об ошибке, возникшей при выполнении последней системной операции (например, операции дискового ввода-вывода). В числовом контексте конструкция $! возвращает мало что говорящий номер ошибки. В строковом контексте переменная $! возвращает сообщение операционной системы об ошибке, например:

Если эта функция не сможет открыть файл из-за его отсутствия, будет выведено сообщение Ошибка при открытии myfile: a file or directory in the path does not exist. Как видите, все понятно. Подобные сообщения в сильной степени помогают понять, что произошло, в каком месте программы и в результате выполнения какой операции. Хорошая диагностика неоценима при локализации программных ошибок.

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

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