【问题标题】:Recursion through a directory tree in PHP通过 PHP 中的目录树递归
【发布时间】:2011-02-01 11:58:53
【问题描述】:

我有一组深度至少为 4 或 5 级的文件夹。我希望尽可能深入地递归目录树,并遍历每个文件。我已经获得了进入第一组子目录的代码,但没有更深,我不知道为什么。有什么想法吗?

$count = 0;
$dir = "/Applications/MAMP/htdocs/site.com";
function recurseDirs($main, $count){
    $dir = "/Applications/MAMP/htdocs/site.com";
    $dirHandle = opendir($main);
    echo "here";
    while($file = readdir($dirHandle)){
        if(is_dir($file) && $file != '.' && $file != '..'){
            echo "isdir";
            recurseDirs($file);
        }
        else{
            $count++;
            echo "$count: filename: $file in $dir/$main \n<br />";
        }
    }
}
recurseDirs($dir, $count);

【问题讨论】:

    标签: php recursion directory


    【解决方案1】:

    查看新的RecursiveDirectoryIterator

    它仍然远非完美,因为您无法对搜索结果和其他内容进行排序,但只需获取文件列表就可以了。

    有一些简单的示例可以帮助您开始阅读本手册:

    <?php
    
    $path = realpath('/etc');
    
    $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), 
    RecursiveIteratorIterator::SELF_FIRST);
    
    foreach($objects as $name => $object){
        echo "$name\n";
    }
    
    ?>
    

    【讨论】:

    • 只有一句话:迭代器的作用正如它的名字所暗示的那样。它迭代一个可迭代的源。这与遍历数组没有什么不同。如果您希望对结果进行排序,那么您必须在 foreach 循环中执行此操作,或者编写/使用函数为您执行此操作。
    • @Gordon 是的。但是,能够立即对结果进行排序和/或过滤是我期望递归目录迭代器提供的一个功能——我知道这可能不在 SPL 的精神中,但仍然如此。实际上,再次需要编写数十行代码(网络上有数百个 sn-ps,质量各不相同)来执行一项非常标准的任务,而其他语言提供现成的功能。有时这让我有点生气。
    • @Pekka 因为现在一切都可以是 Iterable,所以不可能想出一个通用的排序。它怎么知道我希望我的 Person 对象按 $firstName 排序,但我的 Files 按 MTime 排序?您必须编写脚本。如果您想通过泛型表达式查询对象,请查看 PHPLinq。
    • @Gordon true,而不是迭代器的工作。我想我想说的是,我希望看到一个用于文件操作的 PHP 标准库,它比现在可用的更好、更强大。
    • @Pekka 看看github.com/theseer/DirectoryScannergithub.com/sebastianbergmann/php-file-iterator 然后。另外,我目前正在编写一个允许基于文件属性进行过滤的 FilterIterator。
    【解决方案2】:

    调用有错误

    recurseDirs($file);
    

    is_dir($file)
    

    你必须给出完整的路径:

    recurseDirs($main . '/' .$file, $count);
    

    is_dir($main . '/' .$file)
    

    不过,和其他回答者一样,我建议使用RecursiveDirectoryIteretor

    【讨论】:

      【解决方案3】:

      对 is_dir 和 recurseDirs 的调用并不完全正确。您的计数也无法正常工作。这对我有用:

      $dir = "/usr/";
      function recurseDirs($main, $count=0){
          $dirHandle = opendir($main);
          while($file = readdir($dirHandle)){
              if(is_dir($main.$file."/") && $file != '.' && $file != '..'){
                  echo "Directory {$file}: <br />";
                  $count = recurseDirs($main.$file."/",$count); // Correct call and fixed counting
              }
              else{
                  $count++;
                  echo "$count: filename: $file in $main \n<br />";
              }
          }
          return $count;
      }
      $number_of_files = recurseDirs($dir);
      

      注意上面函数调用的变化和函数的新返回值。

      【讨论】:

        【解决方案4】:

        是的:今天我很懒惰,在 Google 上搜索了一个针对递归目录列表的千篇一律的解决方案,结果发现了这个。当我最终编写自己的函数时(至于为什么我什至花时间去谷歌这超出了我的能力——我似乎总是觉得有必要重新发明轮子,没有合适的理由)我倾向于分享我的看法关于这个。

        虽然有支持和反对使用 RecursiveDirectoryIterator 的意见,但我将简单地发表我对一个简单的递归目录函数的看法,并避免参与 RecursiveDirectoryIterator 的政治。

        这里是:

        function recursiveDirectoryList( $root )
        {
        
            /* 
             * this next conditional isn't required for the code to function, but I
             * did not want double directory separators in the resulting array values 
             * if a trailing directory separator was provided in the root path;
             * this seemed an efficient manner to remedy said problem easily...
             */
            if( substr( $root, -1 ) === DIRECTORY_SEPARATOR )
            {
                $root = substr( $root, 0, strlen( $root ) - 1 );
            }
        
            if( ! is_dir( $root ) ) return array();
        
            $files = array();
            $dir_handle = opendir( $root );
        
            while( ( $entry = readdir( $dir_handle ) ) !== false )
            {
        
                if( $entry === '.' || $entry === '..' ) continue;
        
                if( is_dir( $root . DIRECTORY_SEPARATOR . $entry ) )
                {
                    $sub_files = recursiveDirectoryList( 
                        $root . 
                        DIRECTORY_SEPARATOR . 
                        $entry . 
                        DIRECTORY_SEPARATOR 
                    );
                    $files = array_merge( $files, $sub_files );
                }
                else
                {
                    $files[] = $root . DIRECTORY_SEPARATOR . $entry;
                }
            }
        
            return (array) $files;
        
        }
        

        有了这个函数,获取文件数的答案很简单:

        $dirpath = '/your/directory/path/goes/here/';
        
        $files = recursiveDirectoryList( $dirpath );
        
        $number_of_files = sizeof( $files );
        

        但是,如果您不想要相应文件路径数组的开销 - 或者根本不需要它 - 则无需按照建议将计数传递给递归函数。

        可以简单地修改我原来的函数来执行计数:

        function recursiveDirectoryListC( $root )
        {
        
            $count = 0;
        
            if( ! is_dir( $root ) ) return (int) $count;
        
            $dir_handle = opendir( $root );
        
            while( ( $entry = readdir( $dir_handle ) ) !== false )
            {
        
                if( $entry === '.' || $entry === '..' ) continue;
        
                if( is_dir( $root . DIRECTORY_SEPARATOR . $entry ) )
                {
                    $count += recursiveDirectoryListC(
                        $root .
                        DIRECTORY_SEPARATOR .
                        $entry .
                        DIRECTORY_SEPARATOR
                    );
                }
                else
                {
                    $count++;
                }
        
            }
        
            return (int) $count;
        
        }
        

        在这两个函数中,如果目录不可读或发生其他错误,opendir() 函数实际上应该包含在条件中。确保正确执行:

        if( ( $dir_handle = opendir( $dir ) ) !== false ) 
        { 
            /* perform directory read logic */ 
        }
        else
        {
            /* do something on failure */
        }
        

        希望这对某人有所帮助...

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-05
          • 1970-01-01
          • 1970-01-01
          • 2011-07-28
          • 2016-07-22
          • 1970-01-01
          相关资源
          最近更新 更多