Дескрипторы каталогов

Для получения списка имен из заданного каталога также можно воспользоваться дескриптором каталога. Дескрипторы каталога очень похожи на файловые дескрипторы – как по внешнему виду, так и по поведению. Их тоже необходимо открыть (opendir вместо open), прочитать из них данные (readdir вместо readline), а затем закрыть (closedir вместо close). Но вместо чтения содержимого файлов читаются имена файлов (и прочая информация о них). Пример:

my $dir_to_process = "/etc";
opendir DH, $dir_to_process or die "Cannot open $dir_to_process: $!";
foreach $file (readdir DH) {
print "one file in $dir_to_process is $file\n";
}
closedir DH;

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


Например, имена файлов возвращаются без упорядочения1, а в список включаются все файлы, а не только те, которые соответствуют заданному шаблону (например, *.pm, как в примере с глобами). В частности, в него включаются файлы с точкой и специальные записи . и ...2 Таким образом, если нас интересуют только файлы с расширением pm, в цикл включается функция пропуска файлов:

while ($name = readdir DIR) {
next unless $name =~ /\.pm$/;

... Продолжение обработки ...
}

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

next if $name =~ /^\./;

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

next if $name eq "." or $name eq "..";

Мы переходим к той части, в которой многие программисты путаются, так что будьте внимательны. Имена файлов, возвращаемые оператором readdir, не содержат пути. Возвращаются просто имена файлов в каталоге. Таким образом, вы получаете не /etc/passwd, а passwd.


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

opendir SOMEDIR, $dirname or die "Cannot open $dirname: $!";
while (my $name = readdir SOMEDIR) {
next if $name =~ /^\./; # Пропустить файлы, начинающиеся с точки
$name = "$dirname/$name"; # Добавить путь
next unless -f $name and -r $name; # Только файлы с доступом для чтения
...
}

Без обработки операторы проверки файлов будут проверять файлы в текущем каталоге, а не в том каталоге, имя которого хранится в $dirname. Это самая распространенная ошибка при использовании дескрипторов каталогов.

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

Статьи из раздела Perl на эту тему:
Альтернативный синтаксис глобов
Глобы
Изменение временных меток
Изменение разрешений
Операции с файлами и каталогами

Вернуться в раздел: Perl / 12. Операции с каталогами