Обработка всех файлов в каталоге

Задача
Необходимо что-нибудь сделать со всеми файлами в каталоге и в любых его подкаталогах.

Решение
Функция pc_process_dir(), показанная в примере 19.1, возвращает список всех файлов в данном каталоге и ниже.

Пример 19.1. pc_process_dir()
function pc_process_dir($dir_name,$max_depth = 10,$depth = 0) {
if ($depth >= $max_depth) {
error_log("Reached max depth $max_depth in $dir_name.");
return false;
}
$subdirectories = array();
$files = array();
if (is_dir($dir_name) && is_readable($dir_name)) {
$d = dir($dir_name);
while (false !== ($f = $d->read())) {
// пропускаем . и ..
if (('.' == $f) || ('..' == $f)) {
continue;
}
if (is_dir("$dir_name/$f")) {
array_push($subdirectories,"$dir_name/$f");
} else {
array_push($files,"$dir_name/$f");
}
}
$d->close();
foreach ($subdirectories as $subdirectory) {
$files = array_merge($files,pc_process_dir($subdirectory,
$max_depth,$depth+1));
}
}
return $files;
}

Обсуждение
Вот пример: если каталог /tmp содержит файлы a и b, а также каталог c, а каталог /tmp/c содержит файлы d и e, то функция pc_process_dir('/tmp') возвращает массив с элементами /tmp/ a, /tmp/b, /tmp/c/d и /tmp/c/e.

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

$files = pc_process_dir('/tmp');
foreach ($files as $file) {
print "$file was last accessed at ".strftime('%c',fileatime($file))."\n";
}

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


Функция pc_process_dir2(), показанная в примере 19.2, делает это, принимая дополнительный аргумент – имя функции, вызываемой для каждого найденного файла.

Пример 19.2. pc_process_dir2()
function pc_process_dir2($dir_name,$func_name,$max_depth = 10,$depth = 0) {
if ($depth >= $max_depth) {
error_log("Reached max depth $max_depth in $dir_name.");
return false;
}
$subdirectories = array();
$files = array();
if (is_dir($dir_name) && is_readable($dir_name)) {
$d = dir($dir_name);
while (false !== ($f = $d->read())) {
// пропускаем . и ..
if (('.' == $f) || ('..' == $f)) {
continue;
}
if (is_dir("$dir_name/$f")) {
array_push($subdirectories,"$dir_name/$f");
} else {
$func_name("$dir_name/$f");
}
}
$d->close();
foreach ($subdirectories as $subdirectory) {
pc_process_dir2($subdirectory,$func_name,$max_depth,$depth+1);
}
}
}

Функция pc_process_dir2() не возвращает список каталогов; вместо этого функция $func_name вызывается с файлом в качестве аргумента. Ниже показано, как вывести время последнего доступа:

function printatime($file) {
print "$file was last accessed at ".strftime('%c',fileatime($file))."\n";
}
pc_process_dir2('/tmp','printatime');

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

В функциях pc_process_dir() и pc_process_dir2() реализован алгоритм поиска типа «сначала вширь».


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

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

if (is_dir("$dir_name/$f")) {
на:
if (is_dir("$dir_name/$f") && (! is_link("$dir_name/$f"))) {.



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

Статьи из раздела PHP на эту тему:
Изменение прав доступа к файлу или его владельца
Копирование и перемещение файла
Обработка всех файлов в каталоге
Получение и установка меток даты/времени файла
Получение информации о файле

Вернуться в раздел: PHP / 19. Каталоги