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

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

die "Oops! A file called '$filename' already exists.\n"
if -e $filename;

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

warn "Config file is looking pretty old!\n"
if -M CONFIG > 28;

Третий пример более сложен. Допустим, дисковое пространство постепенно заполняется и вместо покупки новых дисков было решено переместить большие, редко используемые файлы на архивные ленты. Мы перебираем список файлов1 и смотрим, у каких файлов размер превышает 100 Кбайт.


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

my @original_files = qw/ fred barney betty wilma pebbles dino bamm-bamm /;
my @big_old_files; # Файлы для перенесения на архивную ленту
foreach my $filename (@original_files) {
push @big_old_files, $filename
if -s $filename > 100_000 and -A $filename > 90;
}

Обратите внимание: управляющая переменная в цикле foreach объявлена с ключевым словом my. Это означает, что область видимости переменной ограничивается самим циклом, поэтому пример будет работать с директивой use strict. Без ключевого слова my будет использоваться глобальная переменная $filename. Все проверки файлов состоят из дефиса и буквы (имени проверки), за которыми следует имя файла или проверяемый дескриптор. Многие проверки возвращают логический признак true/false, но некоторые предоставляют более интересную информацию. Проверки –r, –w, –x и –o сообщают, истинен ли атрибут для действующего идентификатора пользователя или группы3; по сути, речь идет о пользователе, «ответственном» за запущенную программу4.




Эти проверки определяют разрешения по «битам разрешений», установленным для файла в системе. Если в вашей системе применяются списки ACL (Access Control List), они также будут использоваться проверками. Фактически эти проверки сообщают, будет ли система хотя бы пытаться выполнить некоторое действие; если да, то это еще не означает, что оно будет действительно возможно. Например, проверка –w может оказаться истинной для файла на диске CDQROM, хотя запись на него невозможна, а проверка –x может быть истинной для пустого файла, который невозможно выполнить.

Проверка –s возвращает true, если файл не пуст, но это особая разновидность true: в действительности возвращается длина файла в байтах, которая для ненулевого числа интерпретируется как true. В файловой системе UNIX1 существуют семь видов элементов (узлов) файловой системы, представленные семью проверками: –f, –d, –l, –S, –p, –b и –c. Каждый элемент должен относиться к одному из этих типов. Однако для символической ссылки, указывающей на файл, истинный результат возвращается как для –f, так и для –l. Следовательно, если вы хотите знать, является ли элемент символической ссылкой, обычно нужно начинать с –l.




Проверки –M, –A и –C (обратите внимание на верхний регистр) возвращают количество дней, прошедших с момента последней модификации, обращения к элементу или изменения его индексного узла. (Индексный узел содержит всю информацию о файле кроме его содержимого; за подробностями обращайтесь к man-странице системной функции stat или к хорошей книге по внутреннему устройству UNIX.) Срок задается в виде вещественного числа, поэтому если файл был изменен два дня и одну секунду назад, вы можете получить значение 2.00001. («Дни» в этом случае не всегда соответствуют привычной нам системе отсчета; например, если в 1:30 ночи проверить файл, модифицированный в 23:00, значение –M для этого файла составит около 0.1, хотя по нашим представлениям этот файл был изменен «вчера».)

При проверке временных атрибутов файла вы даже можете получить отрицательное значение вида –1.2, которое означает, что метка последнего обращения к файлу сдвинута почти на 30 часов в будущее! Нулевой точкой временной шкалы считается момент запуска программы1, поэтому отрицательное значение может означать, что давно запущенная программа проверяет файл, последнее обращение к которому произошло совсем недавно.


А может быть, временная метка была смещена (случайно или намеренно) на будущее. Проверки –T и –B пытаются определить, является ли файл текстовым или двоичным. Однако люди, разбирающиеся в файловых системах, знают, что бита, определяющего тип файла, не существует (по крайней мере в UNIX-подобных операционных системах) – как же Perl это делает?

Оказывается, Perl жульничает: он открывает файл, просматривает несколько тысяч начальных байт и делает обоснованное предположение. Если среди них обнаруживается много нуль-байтов, необычных управляющих символов и байтов с установленным старшим битом, скорее всего, файл является двоичным. Если же файл не содержит подобных «странностей», он больше похож на текст. Как нетрудно предположить, догадка иногда оказывается ошибочной. Если текстовый файл содержит много шведских или французских слов (с символами, в представлении которых устанавливается старший бит, как в некоторых разновидностях ISOQ885 и даже в Юникоде), Perl может решить, что он имеет дело с двоичным файлом.

Таким образом, система идентификации неидеальна, но если вам нужно только отделить исходный код от откомпилированных файлов или файлы HTML от графики PNG, этих проверок будет достаточно.


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

Проверка –t возвращает true, если заданный дескриптор является TTY – проще говоря, если он интерактивен, то есть не является простым файлом или каналом. Если проверка –t STDIN возвращает true, это обычно означает, что программа может задавать пользователю вопросы. Если возвращается false, программа, скорее всего, получает данные из файла или канала, а не с клавиатуры. Не огорчайтесь, если смысл некоторых проверок остался непонятным – если вы никогда не слышали о них, то, скорее всего, они вам не понадобятся. Но если вам интересно, найдите хорошую книгу по программированию для UNIX.1 (В других системах эти проверки стараются выдать результат, аналогичный результату для UNIX, или undef для недоступных возможностей. Обычно вы сможете правильно понять, что они делают.) Если при проверке файла не указано имя файла или дескриптор (то есть при простом вызове вида –r или –s), по умолчанию в качестве операнда используется файл, имя которого содержится в $_.2 Таким образом, чтобы проверить список имен файлов и узнать, какие из них доступны для чтения, достаточно ввести следующий фрагмент:

foreach (@lots_of_filenames) {
print "$_ is readable\n" if -r; # same as -r $_
}

Но если параметр не указан, будьте внимательны и следите за тем, чтобы то, что следует за проверкой файла, не выглядело как параметр. Например, если потребуется узнать размер файла в килобайтах, а не в байтах, возникает искушение разделить результат –s на 1000 (или 1024):

# Имя файла в $_
my $size_in_K = 0s / 1000; # Сюрприз!

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

my $size_in_k = (s) / 1024; # По умолчанию используется $_

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

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Perl на эту тему:
Поразрядные операторы
Проверка нескольких атрибутов одного файла
Работа с битовыми строками
Сгруппированная проверка файлов
Функции stat и lstat