代码之家  ›  专栏  ›  技术社区  ›  neu242

在PHP中可以加快递归文件扫描速度吗?

  •  9
  • neu242  · 技术社区  · 17 年前

    我一直在尝试复制 Gnu Find (find),但似乎不可能接近它的速度。PHP实现使用的查找时间至少是查找时间的两倍。使用PHP有没有更快的方法?

    编辑:我添加了一个使用SPL实现的代码示例——其性能与迭代方法相当

    EDIT2:当从PHP调用find时,它实际上比本机PHP实现慢。我想我应该对我所拥有的感到满意:)

    // measured to 317% of gnu find's speed when run directly from a shell
    function list_recursive($dir) { 
      if ($dh = opendir($dir)) {
        while (false !== ($entry = readdir($dh))) {
          if ($entry == '.' || $entry == '..') continue;
    
          $path = "$dir/$entry";
          echo "$path\n";
          if (is_dir($path)) list_recursive($path);       
        }
        closedir($d);
      }
    }
    
    // measured to 315% of gnu find's speed when run directly from a shell
    function list_iterative($from) {
      $dirs = array($from);  
      while (NULL !== ($dir = array_pop($dirs))) {  
        if ($dh = opendir($dir)) {    
          while (false !== ($entry = readdir($dh))) {      
            if ($entry == '.' || $entry == '..') continue;        
    
            $path = "$dir/$entry";        
            echo "$path\n";        
            if (is_dir($path)) $dirs[] = $path;        
          }      
          closedir($dh);      
        }    
      }  
    }
    
    // measured to 315% of gnu find's speed when run directly from a shell
    function list_recursivedirectoryiterator($path) {
      $it = new RecursiveDirectoryIterator($path);
      foreach ($it as $file) {
        if ($file->isDot()) continue;
    
        echo $file->getPathname();
      }
    }
    
    // measured to 390% of gnu find's speed when run directly from a shell
    function list_gnufind($dir) { 
      $dir = escapeshellcmd($dir);
      $h = popen("/usr/bin/find $dir", "r");
      while ('' != ($s = fread($h, 2048))) {
        echo $s;
      }
      pclose($h);
    }
    
    7 回复  |  直到 16 年前
        1
  •  4
  •   Greg    17 年前

    我不确定性能是否更好,但您可以使用递归目录迭代器使代码更简单。。。看见 RecursiveDirectoryIterator 和 'SplFileInfo` .

    $it = new RecursiveDirectoryIterator($from);
    foreach ($it as $file)
    {
        if ($file->isDot())
            continue;
    
        echo $file->getPathname();
    }
    
        2
  •  4
  •   user42092 user42092    17 年前

    在你开始改变任何事情之前, 配置您的代码 .

    使用类似 Xdebug

    我唯一的其他建议是使用已经发布的SPL目录迭代器。让内部C代码完成这项工作几乎总是更快。

        3
  •  3
  •   Hawk Kroeger    17 年前

    PHP不能像C一样简单明了地执行。

        4
  •  2
  •   jmucchiello    17 年前

    为什么您希望解释的PHP代码与编译的C版find一样快?速度只有原来的两倍是很好的。

    关于我要添加的唯一建议是在开头执行ob_start(),在结尾执行ob_get_contents(),ob_end_clean()。那个 可以 加快速度。

        5
  •  1
  •   Jason Cohen    17 年前

    保持N个目录流处于打开状态,其中N是目录树的深度。相反,请尝试一次读取整个目录的条目,然后迭代这些条目。至少您可以最大限度地利用桌面I/O缓存。

        6
  •  0
  •   geocar    17 年前

    function list_recursive($dir) { 
      $dir=escapeshellcmd($dir);
      $h = popen("/usr/bin/find $dir -type f", "r")
      while ($s = fgets($h,1024)) { 
        echo $s;
      }
      pclose($h);
    }
    

    然而,可能有一些目录是如此之大,你也不想为此烦恼。考虑以其他方式减慢慢度。例如,只需在会话中保存目录堆栈,就可以检查您的第二次尝试。如果您给用户一个文件列表,只需收集一个页面,然后在会话中为第2页保存其余状态。

        7
  •  0
  •   Ian Gregory    16 年前

    试用 scandir() 正如Jason Cohen所建议的,一次阅读整个目录。以下代码基于php手册注释中的代码 斯堪的纳维亚

     function scan( $dir ){
            $dirs = array_diff( scandir( $dir ), Array( ".", ".." ));
            $dir_array = Array();
            foreach( $dirs as $d )
                $dir_array[ $d ] = is_dir($dir."/".$d) ? scan( $dir."/".$d) : print $dir."/".$d."\n";
     }
    
    推荐文章