Искать и перечислять только определенные каталоги?

Я хочу искать и перечислять только определенные папки и независимо от того, насколько глубоко эти папки хранятся.

Например, ниже показано, как я их структурирую:

local/
     app/
        master/
             models/
             views/
        slaves/
             models/
             views/
     scr/
     models/
     index.php

И я просто хочу перечислить папку models в массив,

local/app/master/models/
local/app/slaves/models/
local/models/

Мой рабочий код,

$directories = array();

$results = array_diff( scandir("local"), array(".", "..") );

foreach ($results as $result)
{
    if (is_dir("local/".$result)) {

        $directories[] = $result;
    }
}

var_dump($directories);

результат,

array
  0 => string 'app' (length=3)
  1 => string 'models' (length=6)
  2 => string 'src' (length=3)

Любые идеи?


person laukok    schedule 15.02.2012    source источник
comment
Сначала создайте массив всех каталогов (см. рекурсивный итератор каталогов), а затем отфильтруйте этот массив, выбрав только те записи, которые вас интересуют (см. фильтр итератор).   -  person hakre    schedule 15.02.2012
comment
Если вам нужны только папки под «моделями», почему вы используете scandir("local") вместо scandir("local/models")? Чтобы вывести список папок на любом уровне, вам понадобится рекурсивная функция.   -  person bfavaretto    schedule 15.02.2012
comment
возможный дубликат Справка по использованию RegexIterator в PHP   -  person Gordon    schedule 15.02.2012


Ответы (3)


Вы сканируете только один уровень в глубину и не проверяете имя папки/файла. Вместо этого вам нужно будет рекурсивно сканировать. Попробуйте что-нибудь вроде этого. Я не тестировал этот код, но вы поняли.

$directories = array();
get_directories('local', $directories);
print_r($directories);

function get_directories($path, &$directories)
{
    $dirs = scandir($path)
    foreach($dirs as $d)
    {
        if(is_dir("$path/$d")
        {
            if($d == 'model')
                $directories[] = "$path/$d";
            elseif($d != '.' && $d != '..')
                get_directories("$path/$d", $directories);
        }
    }
}

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

$ find local/ -name model -type d
person Aleks G    schedule 15.02.2012

Вот еще одно решение без рекурсии, которое будет работать как в php 4, так и в php 5.

<?php
$dir ='local';
while($dirs = glob($dir . '/*', GLOB_ONLYDIR)) {
        $dir .= '/*';
        if (!$d) {
                $d =$dirs;
        } else {
                $d=array_merge($d,$dirs);
        }
}

$dir_to_match = 'models';

$result = array();
foreach ($d as $dir_name) {
        if (preg_match('#/' . $dir_to_match . '$#', $dir_name)) {
                $result[] = $dir_name;
        }
}
var_dump($result);
?>
person alex347    schedule 15.02.2012
comment
Почему вы все еще разыгрываете эту карту в 2012 году? - person Alix Axel; 20.10.2012

person    schedule
comment
Подсказка: SplFileInfo::getBasename - person hakre; 15.02.2012
comment
@hakre Интересно - это в основном делает то, что делает строка $dir = ...? Документы, похоже, не предполагают, что он делает что-то отличное от basename() - что он делает по-другому? - person DaveRandom; 15.02.2012
comment
Хорошо, однако потребление памяти при этом может быть огромным, если у него очень большое дерево каталогов с несколькими совпадениями. - person Aleks G; 15.02.2012
comment
if ($path->isDir() && $path->getBasename() === 'models') $result[] = (string) $path; - вам не нужно заботиться ни о типе косой черты, ни об обрезке. Это просто более ясно, что делает код. - person hakre; 15.02.2012
comment
@AleksG Откуда такое потребление памяти? Насколько я понимаю, RecursiveDirectoryIterator считывает файловую систему в режиме реального времени, когда вы зацикливаете ее, а не загружаете всю информацию в память... разве это не правильно?# - person DaveRandom; 15.02.2012
comment
@AleksG: RecursiveIteration не потребляет много памяти (гораздо меньше, чем рекурсивные вызовы функций, поскольку SPL использует стеки внутри вместо рекурсивных вызовов функций. Кроме того, FilterIterator (не показано в этом ответе) еще больше уменьшит использование памяти, поскольку нет надмножества тогда все каталоги вообще хранятся в памяти, но в любом случае это не относится к этому ответу, только нужные строки хранятся в массиве $result. - person hakre; 15.02.2012
comment
DaveRandom, @hakre Меня беспокоит не RecursiveIterator, а создание полного массива всех рекурсивных файлов/каталогов. Если бы я построил такой массив в своей музыкальной коллекции, в нем было бы более миллиона записей. - person Aleks G; 15.02.2012
comment
@AleksG Но это именно то, что хочет сделать ОП - построить массив всех совпадающих объектов. Если это приводит к огромному массиву, решение этой проблемы выходит за рамки исходного вопроса. - person DaveRandom; 15.02.2012
comment
Я думаю, что я здесь запутался - я имел в виду, что массив ВСЕХ файлов будет занимать память, а не массив совпадений. В оригинальном комментарии hakre говорится о создании массива всех путей. Я не уверен, как внутренне работает RecursiveIterator, но, надеюсь, он не создает такой массив и выполняет итерацию на лету. - person Aleks G; 15.02.2012
comment
@AleksG: Нет, только каталоги с models в качестве базового имени. Все остальное нигде не хранится. Массив всех файлов был бы неитеративным подходом, чтобы сделать проблему менее сложной и показать путь. Я уже связал итераторы, так что было не очень точно сказать массив в комментарии. С итераторами у вас нет массива, но у вас есть хороший foreach и вы относитесь к нему как к массиву. И у вас нет рекурсивных вызовов функций, как в вашем ответе, что часто является преимуществом (ваш тоже работает, он также решает проблему правильным способом). - person hakre; 15.02.2012
comment
@hakre: Спасибо за объяснение. Я знал, что что-то упускаю. У меня никогда не было необходимости использовать итератор, поэтому я не был уверен, как он работает. - person Aleks G; 15.02.2012