2

次のスニペットを使用して、現在のディレクトリの内容を再帰的にマップします。

$files = new RecursiveIteratorIterator
(
    new RecursiveDirectoryIterator('./',
        FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS),
    RecursiveIteratorIterator::SELF_FIRST
);

$files = array_values(array_map('strval', iterator_to_array($files)));

次のようなものを返します。

Array
(
    [0] => ./1.png
    [1] => ./a.php
    [2] => ./adminer
    [3] => ./adminer/adminer.css
    [4] => ./adminer/adminer.php
)

関数に存在する動作を取得RecursiveDirectoryIterator/FilesystemIteratorエミュレートする方法はありますか? マニュアルから:GLOB_MARKglob()

GLOB_MARK - 返された各ディレクトリにスラッシュを追加します。

次のようにするだけでそれをエミュレートできることを知っています。

foreach ($files as $key => $value)
{
    $files[$key] .= (is_dir($value) ? '/' : '');
}

しかし、それには (不必要に?) ディスクに何度もアクセスする必要があります。パスがディレクトリか通常のファイルかをすばやく判断する方法を探しています。末尾のスラッシュが理想的なソリューションのようです。

これを使用して、数万 (数百ではないにしても) のファイルをトラバースする予定であるため、パフォーマンスが重要です。

おまけの質問: ディレクトリのみを (再帰的に) 取得する方法はありますか?

4

2 に答える 2

4

GlobMarkIterator独自の利点を作成できます。

  • 終了スラッシュをディレクトリに戻しますGLOB_MARK
  • array_mapwithを使用strvalして文字列に変換する必要はありません
  • 余分なforeachループはありませんis_dir
  • それでもオリジナルと同じくらい速い
  • はい、私はだまされたことを知っています

$ri = new RecursiveIteratorIterator(new GlobMarkIterator('./', FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS), RecursiveIteratorIterator::SELF_FIRST);
$files = array_values(iterator_to_array($ri));

echo "<pre>";
print_r($files);

出力

Array
(
    [0] => ./test/backups/ <----------- Note ending slash 
    [1] => ./test/CSV/
    [2] => ./test/CSV/abc.csv
    [3] => ./test/final/
    [4] => ./test/thumb/
    [5] => ./test/thumb/a.png
    [6] => ./test/thumb/s.svg
    [7] => ./test/thumb/sample.svg
)



おまけの質問: ディレクトリのみを (再帰的に) 取得する方法はありますか?

これは別の質問だったはずですが、まったく同じです....満足してこれに賞金をかけないことを願っています

解決 :

$ri = new RecursiveIteratorIterator( new GlobMarkDirectory('./test'), RecursiveIteratorIterator::SELF_FIRST);
$dir = array_values(iterator_to_array($ri));

echo "<pre>";
print_r($dir);

出力

Array
(
    [0] => ./test/backups/
    [1] => ./test/CSV/
    [2] => ./test/final/
    [3] => ./test/thumb/
)

使用クラス

GlobMarkIterator

class GlobMarkIterator extends RecursiveDirectoryIterator {
    function current() {
        return $this->isDir() ? $this->getPathname() . "/" : $this->getPathname();
    }
}

GlobMarkDirectoryクラス

class GlobMarkDirectory  extends RecursiveFilterIterator {
    public function __construct($path) {
        parent::__construct(new GlobMarkIterator($path, FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS));
    }
    public function accept() {
        return $this->getInnerIterator()->isDir();
    }
    public function getChildren() {
        return new GlobMarkDirectory($this->getInnerIterator()->getPathname());
    }
}



EDIT ..気にせず、速度とオーバーヘッドのためempty dirに使用したくない場合は、別の解決策がありますisDir

解決

$ri = new RecursiveIteratorIterator(new GlobMarkFastDirectory  (__DIR__), RecursiveIteratorIterator::SELF_FIRST);
$dir = array_values(array_unique(iterator_to_array($ri)));

GlobMarkFastDirectory

class GlobMarkFastDirectory  extends RecursiveDirectoryIterator {
    function current() {
        return dirname($this->getPathname())  ."/";
    }
}
于 2012-10-20T12:45:12.457 に答える