2013-11-14 5 views
9

Я новичок в PHP-кодировании, и здесь я ищу самый быстрый способ сделать рекурсивный поиск по всем каталогам для массива строк.Рекурсивно искать все каталоги для массива строк в php

Я делаю так

$contents_list = array("xyz","abc","hello"); // this list can grow any size 
$path = "/tmp/"; //user will give any path which can contain multi level sub directories 

$dir = new RecursiveDirectoryIterator($path); 

foreach(new RecursiveIteratorIterator($dir) as $filename => $file) { 
    $fd = fopen($file,'r'); 
    if($fd) { 
     while(!feof($fd)) { 
      $line = fgets($fd); 
      foreach($contents_list as $content) { 
       if(strpos($line, $content) != false) { 
        echo $line."\n"; 
       } 
      }   
     } 
    } 
    fclose($fd); 
} 

Здесь я рекурсивно перебирает все каталоги, а затем снова на каждом файле перебрать содержимое массива для поиска.

Есть ли лучший способ сделать поиск? Пожалуйста, предложите для более быстрой альтернативы.

Благодаря

+2

, что о 'scandir' – zzlalani

+0

Был аналогичный вопрос здесь: http://stackoverflow.com/questions/10663641/grep-with-f-like -in-php Может ли это помочь? – ErnestV

ответ

8

Если вам разрешено выполнять команды оболочки в среде (и при условии, что вы используете свой сценарий на * Никс), можно вызвать команду родной Grep рекурсивно. Это даст вам самые быстрые результаты.

$contents_list = array("xyz","abc","hello"); 
$path = "/tmp/"; 
$pattern = implode('\|', $contents_list) ; 
$command = "grep -r '$pattern' $path"; 
$output = array(); 
exec($command, $output); 
foreach ($output as $match) { 
    echo $match . '\n'; 
} 

Если disable_functions директива действует, и вы не можете позвонить Grep, вы можете использовать подход с RecursiveDirectoryIterator и чтение строки файлов по линии, используя StrPos на каждой строке. Обратите внимание: strpos требует строгой проверки равенства (используйте !== false вместо != false), иначе вы пропустите совпадения в начале строки.

Немного более быстрый способ - использовать глобус, чтобы получить список файлов, и сразу же прочитать эти файлы, а не сканировать их по строкам. Согласно моим тестам, этот подход даст вам преимущество 30-35% времени по сравнению с вашим.

function recursiveDirList($dir, $prefix = '') { 
    $dir = rtrim($dir, '/'); 
    $result = array(); 

    foreach (glob("$dir/*", GLOB_MARK) as &$f) { 
     if (substr($f, -1) === '/') { 
      $result = array_merge($result, recursiveDirList($f, $prefix . basename($f) . '/')); 
     } else { 
      $result[] = $prefix . basename($f); 
     } 
    } 

    return $result; 
} 

$files = recursiveDirList($path); 
foreach ($files as $filename) { 

    $file_content = file($path . '/' . $filename); 
    foreach ($file_content as $line) { 
     foreach($contents_list as $content) { 
      if(strpos($line, $content) !== false) { 
       echo $line . '\n'; 
      } 
     } 
    } 
} 

Кредит на рекурсивной функции Глоб переходит к http://proger.i-forge.net/3_ways_to_recursively_list_all_files_in_a_directory/Opc

Подводя итог с точки зрения производительности вы следующие рейтинги (результаты в секундах для Фарли большой каталог, содержащий ~ 1200 файлов recusively, используя два общие текстовые шаблоны): GREP

  1. вызова через Exec() - 2.2015s
  2. использование рекурсивной glob и чтение файлов с file() - 9.4443s
  3. использование RecursiveDirectoryIterator и читать файлы с readline() - 15.1183s