13

私は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);
}

ここでは、すべてのディレクトリを再帰的に反復し、各ファイルで内容配列を反復して検索しています。

種類の検索を行うためのより良い方法はありますか? より速い代替案を提案してください。

ありがとう

4

2 に答える 2

13

環境でシェル コマンドを実行することが許可されている場合 (およびスクリプトを *nix で実行していると仮定した場合)、ネイティブの 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 を呼び出すことができない場合は、各行で strpos を使用して、ファイルを行ごとに読み取り、アプローチを使用できますRecursiveDirectoryIteratorstrposには厳密な等価性チェック (!== falseの代わりに使用) が必要であることに注意してください!= false。そうしないと、行頭の一致がスキップされます。

少し高速な方法は、glob を再帰的に使用してファイルのリストを取得し、それらのファイルを行ごとにスキャンする代わりに一度に読み取ることです。私のテストによると、このアプローチは、あなたのアプローチよりも約 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にあります

要約すると、パフォーマンスに関して次のランキングがあります (2 つの一般的なテキスト パターンを使用して、約 1200 個のファイルを再帰的に含む非常に大きなディレクトリの結果を数秒で表示します)。

  1. exec() 経由で grep を呼び出す - 2.2015s
  2. -9.4443sで再帰的globおよび読み取りファイルを使用するfile()
  3. -15.1183sRecursiveDirectoryIteratorでファイルを使用および読み取りreadline()
于 2013-11-14T09:17:59.357 に答える