【问题标题】:Sorting files per directory using SPL's DirectoryTreeIterator使用 SPL 的 DirectoryTreeIterator 对每个目录的文件进行排序
【发布时间】:2011-07-22 00:13:12
【问题描述】:

我发现了几个与 SPL 迭代器相关的问题(this onethis question),但我不确定它们对我的情况是否有帮助,因为我使用的是相当高级别的扩展RecursiveIteratorIterator; DirectoryTreeIterator

有人可以告诉我如何更改 DirectoryTreeIterator 或如何在迭代器输出后按目录对返回的数组进行排序吗?

如果可以使用 .htaccess 等,直接在 Apache 服务器上正确排序文件的方法也是我的一个选择。

这是来自 SPL 的 DirectoryTreeIterator 的代码:

/** @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);;
    }
}

澄清我为什么使用上面的代码是因为它完全符合我的需求。我想生成一个以空格为前缀的递归目录树——Marcus Boerger 的原始代码示例添加了一些 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
[...]

所以我想我正在寻找的解决方案是每次对子目录进行索引并添加到​​目录树时调用排序方法的某种方式。

我希望我说得更清楚一些,作为一个非母语人士,有时很难将想法变成连贯的句子(甚至是单词)。

【问题讨论】:

    标签: php sorting recursion iterator spl


    【解决方案1】:

    不了解 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();
    }
    

    【讨论】:

      【解决方案2】:

      好吧,我不确定你从哪里得到这个类,但它正在做一些非常混乱的事情(至少可以说包括一些错误)。虽然它使用 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);
      

      这是一个非常简单的递归解析器,并且在每个级别上进行自然排序。

      【讨论】:

      • 我认为迭代器不是 SPL 的一部分是正确的,但它在示例中列出:php.net/~helly/php/ext/spl/… 和此处:php.net/~helly/php/ext/spl/directorytreeiterator_8inc.html
      • @mensch 好吧,这只是一个示例用法。更不用说您似乎已经修改了它(因此引入了我正在谈论的错误)。如果你举一个你所追求的例子,也许我们可以更好地帮助......
      • 你说得对,我稍微修改了代码,使其输出空格而不是 ASCII 字符。乍一看,我无法发现原始示例和我的版本之间的任何其他差异。我选择合并示例的原因是因为我想生成以空格为前缀的目录树。我将用一些关于我想要完成的任务的额外信息来更新我的问题。
      • 感谢一百万!总是很难理解递归。我刚刚用您的 BuildTree 方法替换了旧代码,它现在运行良好。我用 $file->getPathname() 替换了 $file->getBaseName() 因为我需要目录的完整路径。
      猜你喜欢
      • 2011-07-04
      • 1970-01-01
      • 2020-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多