Список файлов и каталогов, в PHP

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

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

Представим себе структуру каталога, которая выглядит, как показано ниже:



\---manager
|
\---user
|   \---document.txt
|   \---data.dat
|   \---style.css
|---article.txt
|---master.dat
|---script.php
|---test.dat
|---text.txt


Основное решения

Первый набор подходов демонстрирует использование функции glob() , совмещение функций opendir() , readdir() и closedir() , и функции scandir() .

Использование функции glob()

Первая функция, для осуждения, является glob() , которая позволяет выполнять поиск имен с использованием подстановки символов, общие для самых известных оболочек. Функция имеет два параметра:

Рассмотрим несколько примеров! Для поиска в каталоге для всех файлов и каталогов, которые заканчиваются TXT. , вы должны написать:



<?php
$filelist = glob("*.txt"); ?>


Если отобразить списком $filelist, на выходе будет:



array (
  0 => 'article.txt',
  1 => 'text.txt'
)


Если вы хотите получить список файлов и каталогов, которые начинаются с “te” , код будет такой:



<?php
$filelist = glob("te*"); ?>


На выходе:



array (
  0 => 'text.txt'
)


Чтобы получить список каталогов, которые содержат только “ma” , код будет такой:



<?php
$filelist = glob("*ma*", GLOB_ONLYDIR); ?>


В последнем примере, выход:



array (
  0 => 'manager'
)


Обратите внимание, что последний пример использует постоянно GLOB_ONLYDIR как опционально второй параметр, исключается из-за этого файл называется master.dat . Хотя функция glob() очень проста в использовании, это не всегда помогает. Например, она не имеет флаг, чтобы извлечь только файлы (а не каталоги), которые соответствуют заданному шаблону.

Использование opendir(), readdir(), и closedir()

Второй подход для чтения файлов и каталогов. Для начала нужно обсудить, что из себя представляют функции opendir() , readdir() , и closedir() .

opendir() открывает каталог и возвращает дескриптор соединения. Как только обработка извлекается, можно будет использовать readdir() . При каждом вызове, эта функция даст имя следующего файла или каталога внутри открытого каталога. Когда все имена были восстановлены, функция возвращает false. Чтобы закрыть обработку, используется  closedir() .

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

В следующем примере возвращается список всех файлов и каталогов, которые начинаются с “te” :



<?php
$filelist = array();
if ($handle = opendir(".")) {
    while ($entry = readdir($handle)) {
        if (strpos($entry, "te") === 0) {
            $filelist[] = $entry;
        }
    }
    closedir($handle);
}?>


Выход такой же, как и в предыдущем примере. Но если вы запустите приведенный выше код и выведите значения $entry , вы увидите как это работает, и то что он содержит некоторые странные записи: “.” и “..” . Эти два виртуальных каталога, которые вы найдете в каждом каталоге файловой системы. Они представляют собой текущий каталог и родительский каталог (до уровня папки) соответственно.

Второй пример показывает, как получить только те файлы, которые содержатся в указном пути.



<?php
$filelist = array();
if ($handle = opendir(".")) {
    while ($entry = readdir($handle)) {
        if (is_file($entry)) {
            $filelist[] = $entry;
        }
    }
    closedir($handle);
} ?>


Как вы уже догадались, с помощью приведенного выше кода, получается следующий результат:



array (
  0 => 'article.txt',
  1 => 'master.dat',
  2 => 'script.php',
  3 => 'test.dat',
  4 => 'text.txt'
)


Использование scandir()

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

Этот пример показывает, как извлечь файлы и каталоги, которые начинаются со строки “te” :



<?php
$entries = scandir(".");
$filelist = array();
foreach($entries as $entry) {
    if (strpos($entry, "te") === 0) {
        $filelist[] = $entry;
    }
} ?>


Давайте использовать итераторы SPL

Теперь давайте поговорим о некоторых SPL итераторы . Но прежде, чем углубляться в их использовании, позвольте мне представить их и библиотеки SPL. SPL предоставляет ряд классов для объектно-ориентированных структур данных, итераторы, обработчики файлов и другие функции.

Одним из плюсов является то, что итераторы классы и поэтому вы можете расширить их, чтобы лучше соответствовать вашим потребностям. Еще одним преимуществом является то, что у них есть собственные методы, которые являются действительно полезными в достижении многих общих задач с которыми вы можете столкнуться. Возьмем в качестве примера  FilesystemIterator среди readdir() , оба из них будут использованы в цикле, но при использовании ввода readdir() ничего не будет, но в строку, используя FilesystemIterator у вас есть объект, который может предоставить вам много информация о том, какой файл или каталог (размер, владелец, права доступа и так далее).

Конечно, PHP может предоставить Вам информацию с помощью той же функции, такую как размер файла filesize() и fileowner() , но PHP5 получил свой подхода к ООП. Итак, в заключение, я советую следовать новой передовой практики в языке. В случае, если вам нужно больше общей информации о итераторов SPL, взгляните на страницу Использование итераторы SPL .

Как уже было сказано в начале, будет показано использование FilesystemIterator , RecursiveDirectoryIterator и GlobIterator . Первый из них исходит от DirectoryIterator в то время как другие исходят от FilesystemIterator . Они все имеют одинаковый конструктор, который имеет всего два параметра:

  • $path (обязательный): Путь к файловой системе элемента для итерации
  • $flags (по желанию): Один или несколько флагов, перечисленные в официальной документации

Что на самом деле отличает подход в итераторов, и что они используют для навигации по заданному пути.

FilesystemIterator

Использование FilesystemIterator довольно простое. Чтобы увидеть его в действии, я покажу два примера. В первом, я буду искать все файлы и каталоги, которые начинаются со строки “te” , а второй будет использовать другой итератор, RegexIterator , чтобы найти все файлы и каталоги, которые содержат  в конце  «t.dat» или «t.php» . RegexIterator используется для фильтрации другого итератора на основе регулярных выражений.



<?php
$iterator = new FilesystemIterator(".");
$filelist = array();
foreach($iterator as $entry) {
    if (strpos($entry->getFilename(), "te") === 0) {
        $filelist[] = $entry->getFilename();
    }
}


В коде выше, результат будет таким же, как и в предыдущих примерах.

Второй пример, который использует RegexIterator :



<?php
$iterator = new FilesystemIterator(".");
$filter = new RegexIterator($iterator, '/t\.(php|dat)$/');
$filelist = array();
foreach($filter as $entry) {
    $filelist[] = $entry->getFilename();
}


В этом случае на выходе будет:



array (
  0 => 'script.php',
  1 => 'test.dat'
)


RecursiveDirectoryIterator

RecursiveDirectoryIterator предоставляет интерфейс для итерации рекурсивно по каталогам файловой системы. Благодаря своей цели, он имеет некоторые полезные методы, такие как GetChildren() и HasChildren() , которые возвращают итератор для текущей записи, если это каталог является каталогом с записью . Чтобы увидеть в действии, RecursiveDirectoryIterator и GetChildren() , Я перепишу последний пример, и получу тот же результат:



<?php
$iterator = new RecursiveDirectoryIterator('.');
$filter = new RegexIterator($iterator->getChildren(), '/t\.(php|dat)$/');
$filelist = array();
foreach($filter as $entry) {
    $filelist[] = $entry->getFilename();
}


Заключение

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

  • Функция glob()  решение из одной строки, но без управления на выходе.
  • Решения с использованием opendir() , readdir() , и closedir() немного многословный и нуждается в пост-фильтрации, но является более гибким.
  • Функция scandir() требует пост-фильтрацию, хорошо, но не может управлять обработкой.
  • Если вы хотите использовать объектно-ориентированный подход, вы должны использовать библиотеки SPL. Более того, вы можете расширить классы в соответствии с вашими потребностями.
  • В то время как GlobIterator имеет возможность сделать предварительную фильтрацию, другие могут сделать то же самое в удобный способ использования RegexIterator .

Если вы знаете другие подходы, поделитесь с нами. Обмен знаниями всегда приветствуется.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML -теги и атрибуты: <a href= http://pixelcom.crimea.ua/"" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>