Сортировка файлов по каталогу с использованием SPL's DirectoryTreeIterator - PullRequest
0 голосов
/ 24 марта 2011

Я нашел пару вопросов ( этот и этот вопрос ), связанных с итераторами SPL, но я не уверен, что они полезны в моем случае, так какЯ использую довольно высокое расширение RecursiveIteratorIterator;DirectoryTreeIterator.

Может кто-нибудь показать мне, как изменить DirectoryTreeIterator или как отсортировать возвращенный массив по каталогу после того, как он был выведен итератором?

Методправильная сортировка файлов непосредственно на сервере Apache - также вариант для меня, если это возможно, например, с использованием .htaccess.

Это код DirectoryTreeIterator из SPL:

/** @file directorytreeiterator.inc
 * @ingroup Examples
 * @brief class DirectoryTreeIterator
 * @author  Marcus Boerger
 * @date    2003 - 2005
 *
 * SPL - Standard PHP Library
 */

/** @ingroup Examples
 * @brief   DirectoryIterator to generate ASCII graphic directory trees
 * @author  Marcus Boerger
 * @version 1.1
 */

class DirectoryTreeIterator extends RecursiveIteratorIterator
{
    /** Construct from a path.
     * @param $path directory to iterate
     */
    function __construct($path) {
        parent::__construct(
            new RecursiveCachingIterator(
                new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME
                ), 
                CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD
            ), 
            parent::SELF_FIRST
        );
    }

    /** @return the current element prefixed with ASCII graphics
     */ 
    function current() {
        $tree = '';
        for ($l=0; $l < $this->getDepth(); $l++) {
            $tree .= $this->getSubIterator($l)->hasNext() ? ' ' : ' ';
        }
        return $tree . ($this->getSubIterator($l)->hasNext() ? ' ' : ' ') 
               . $this->getSubIterator($l)->__toString();
    }

    /** Aggregates the inner iterator
     */ 
    function __call($func, $params) {
        return call_user_func_array(array($this->getSubIterator(), $func), $params);;
    }
}

Чтобы пояснить, почему я использую код выше, потому что он точно соответствует моим потребностям.Я хочу создать рекурсивное дерево каталогов с префиксом пробелов - оригинальный пример кода Маркуса Бергера добавляет некоторые элементы ASCI.Проблема в том, что я не контролирую сортировку файлов и каталогов, поэтому я хотел бы, чтобы дерево каталогов выглядело так:

dir001
  subdir001
    subdir002
      subfile001.jpg
  file001.png
  file002.png
  file003.png
dir002
  apple.txt
  bear.txt
  contact.txt
dir003
[...]

Вместо этого списки, возвращаемые итератором, не сортируютсявообще, и это показывает мне что-то вроде этого:

dir002
  bear.txt
  apple.txt
  contact.txt
dir001
  subdir001
    subdir002
      subfile001.jpg
  file002.png
  file001.png
  file003.png
dir003
[...]

Так что я думаю, что решение, которое я ищу, это какой-то способ вызова метода сортировки каждый раз, когда подкаталог индексируется и добавляется в дерево каталогов.

Надеюсь, я сделал это несколько яснее, поскольку не говорящему на нативе иногда трудно выразить мысли в связные предложения (или даже слова в этом отношении).

Ответы [ 2 ]

3 голосов
/ 24 марта 2011

Ну, я не уверен, откуда у вас этот класс, но он делает некоторые довольно запутанные вещи (в том числе несколько ошибок, если не сказать больше). И хотя он использует SPL, это не класс SPL.

Теперь я не уверен на 100%, что вы имеете в виду под "сортировкой", но, если предположить, что вы говорите о естественной сортировке, почему бы не сгладить массив, а затем отсортировать его?

$it = new RecursiveTreeIterator(
    new RecrusiveDirectoryIterator($dir),
    RecursiveTreeIterator::BYPASS_KEY,
    CachingIterator::CALL_TOSTRING
);
$files = iterator_to_array($it);
natsort($files);
echo implode("\n", $files);

или

$it = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($dir),
    RecursiveIteratorIterator::SELF_FIRST
);
$files = iterator_to_array($it);
$files = array_map(function($file) { return (string) $file; }, $files);
natsort($files);
echo implode("\n", $files);

Редактировать: Основываясь на ваших изменениях, вот как я бы решил:

function BuildTree($it, $separator = '  ', $level = '') {
    $results = array();
    foreach ($it as $file) {
        if (in_array($file->getBasename(), array('.', '..'))) {
            continue;
        }
        $tmp = $level . $file->getBaseName();
        if ($it->hasChildren()) {
            $newLevel = $level . $separator;
            $tmp .= "\n" . BuildTree($it->getChildren(), $separator, $newLevel);
        }
        $results[] = $tmp;
    }
    natsort($results);
    return implode("\n", $results);
};
$it = new RecursiveDirectoryIterator($dir);
$tree = BuildTree($it);

Это довольно простой рекурсивный парсер, который выполняет естественную сортировку на каждом уровне.

0 голосов
/ 24 марта 2011

Не знаю об итераторах SPL, но для вашего итератора вы должны поместить элементы в массив, затем отсортировать их и добавить в $ tree.Я изменил функцию current , но не протестировал ее:

function current()
{
    $tree = '';

    $treeitems = array();
    for ($l=0; $l < $this->getDepth(); $l++) {
        //NOTE: On this line I think you have an error in your original code:
        //      This ? ' ' : ' ' is strange
        $treeitems[] = $this->getSubIterator($l)->hasNext() ? ' ' : ' ';
    }
    $treeitems.sort();
    for each ($treeitems as $treeitem)
        $tree .= $treeitem;

    return $tree . ($this->getSubIterator($l)->hasNext() ? ' ' : ' ') 
           . $this->getSubIterator($l)->__toString();
}
...