Рекурсивная обработка всех файлов каталога
Проблема
Требуется выполнить некоторую операцию с каждым файлом и подкаталогом некоторого каталога.
Решение
Воспользуйтесь стандартным модулем File::Find.
use File::Find;
sub process_file {
# делаем то, что хотели
}
find(\&process_file, @DIRLIST);
Комментарий
Модуль File::Find обеспечивает удобные средства рекурсивной обработки файлов.
Просмотр каталога и рекурсия организуются без вашего участия. Достаточно передать find
ссылку на функцию и список каталогов. Для каждого файла в этих каталогах find вызовет
заданную функцию.
Перед вызовом функции find переходит в указанный каталог, имя которого по отношению к
начальному каталогу хранится в переменной $File::Find::dir. Переменной $_ присваивается
базовое имя файла, а полный путь к этому файлу находится в переменной $File::Find::name.
Ваша программа может присвоить $File::Find::prune истинное значение, чтобы функция find не
спускалась в только что просмотренный каталог.
Использование File::Find демонстрируется следующим простым примером. Мы передаем find
анонимную подпрограмму, которая выводит имя каждого обнаруженного файла и добавляет к
именам каталогов /:
@ARGV = qw(.) unless @ARGV;
use File::Find:
find sub { print $File::Find::name, -d && '/', "\n" }, @ARGV;
Для вывода / после имен каталогов используется оператор проверки -d, который при
отрицательном результате возвращает пустую строку ' '.
Следующая программа выводит суммарный размер всего содержимого каталога. Она передает
find анонимную подпрограмму для накопления текущей суммы всех рассмотренных ей файлов.
Сюда входят не только обычные файлы, но и все типы индексных узлов, включая размеры
каталогов и символических ссылок. После выхода из функции find программа выводит накопленную сумму.
use File::Find:
@ARGV = ('.') unless (3ARGV;
my $sum = 0;
find sub { $sum += -s }, @ARGV;
print "@ARGV contains $sum bytes\n";
Следующий фрагмент ищет самый большой файл в нескольких каталогах:
use File::Find;
@ARGV = ('.') unless @ARGV;
my ($saved_size, $saved_name) = (-1, '');
sub biggest {
return unless -f && -s _ > $saved_size;
$saved_size = -s _;
$saved_name = $File::Find::name;
}
find(\&biggest, @ARGV);
print "Biggest file $saved_name in @ARGV is $saved_size bytes long.\n";
Переменные $saved_size и $saved_name используются для хранения имени и размера
самого большого файла. Если мы находим файл, размер которого превышает размер самого
большого из просмотренного до настоящего момента, сохраненное имя и размер заменяются
новыми значениями. После завершения работы find выводится имя и размер самого большого
файла в весьма подробном виде. Вероятно, более практичная программа ограничится
выводом имени файла, его размера или и того и другого. На этот раз мы воспользовались
именованной функцией вместо анонимной, поскольку она получилась относительно большой.
Программу нетрудно изменить так, чтобы она находила файл, который изменялся последним:
use File::Find;
@ARGV = ('.') unless @ARGV;
my ($age, $name);
sub youngest {
return if defined $age && $age > -M;
$age = (stat(_))[9];
$name = $File::Find::name;
}
find(\&youngest, @ARGV);
print "$name " . scalar(localtime($age)) . "\n";
См. также
Proverte kod v komentariyah gde pro list tam oshibki detskie
Оставить комментарий:
|
|