unoh.github.com

dir_walk_recursive?

Sun Jul 29 19:01:53 -0700 2007

こんにちは。先々週、入社したbokkoです。

普段はbokkoとかcubicdaiyaとか名乗っています。近々、「就職祝い」として、フルボッコの会が開かれるそうなのですが、大学時代の先輩がたくさん来るそうなので、期待と不安が半々といったところです。

それはそれとして、アプリケーション内で、指定したディレクトリ以下のファイル全部に対して、何らかの処理を行いたい時がたまにあると思います。こういう場合、ディレクトリかファイルかで処理を分け、ループと再帰でぶん回したりしますが、去年、これを何回も書く機会があって面倒になったことがあったので、ディレクトリの規模があまり大きくない場合は、

function divGeneric($dir, $f, $arg){
    if(!is_dir($dir)) return false;
    if($hd = opendir($dir)){
        while(false !== $file = readdir($hd)){
            if($file != "." && $file != ".."){
                $f($dir,$file,$arg,$f);
            }
        }
        closedir($hd);
    }
    return $arg;
}


↑のような関数を用意して、実行したい処理を引数で渡すだけで済むようにしています。例えば、あるディレクトリ以下の全ファイルを1つの配列に入れるような場合は、以下のように書きます。


$f = create_function('$dir,$file,&$array,$f', 
                     'if(is_dir($dir."/".$file)){
                          $array = divGeneric($dir."/".$file, $f, $array);
                      }
                      else{
                          $array[] = $dir."/".$file;
                      }
                     ');
$ret = divGeneric($root_dir, $f, array());


こんな感じで、array_walk_recursiveならぬ, dir_walk_recursiveっぽいことができます。関数の名前が全然違いますが、気にしないでください。ただ、このやり方はうまくいかなかったときのデバッグが面倒なので、create_function内に書く処理はあんまり長くならないようにした方がいいかもしれません。

■ほかの言語の場合



RubyとPythonの例は前に私が書いたのがこちらにあります。ただ、Pythonでは、lambdaに単一の式しか渡せない(それがいいか悪いかどうかはまた別のお話)ので、少し強引に書いてます。


■余談



PHP5ではscandirがあるので、もう少しスマートに書けます。



追記(7/30)

コードにちょっと間違いがあったので、修正しました。
手元のコードをよく見たらdieじゃなくて、return false;でした。