php - 使用 FilesystemIterator 将尾部斜杠应用于文件夹

标签 php filesystems iterator spl

使用以下代码片段递归映射当前目录的内容:

$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() 中存在的 GLOB_MARK 行为功能?来自手册:

GLOB_MARK - Adds a slash to each directory returned.

我知道我可以通过简单地执行以下操作来模仿:

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

但这需要(不必要的?)多次访问磁盘。我正在寻找一种方法来快速确定路径是目录还是常规文件,结尾斜杠似乎是理想的解决方案。

我计划用它来遍历数十(如果不是数百)数千个文件,因此性能至关重要。

额外问题:有没有办法只获取目录(递归)?

最佳答案

您可以创建自己的GlobMarkIterator优点:

  • 将结束斜杠返回到目录,就像 GLOB_MARK
  • 无需使用 array_mapstrval 将其转换为字符串
  • 没有额外的 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());
    }
}



编辑..如果您不关心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())  ."/";
    }
}

关于php - 使用 FilesystemIterator 将尾部斜杠应用于文件夹,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12988204/

相关文章:

linux - 在 Linux 上,文件是由哪个程序创建的?

linux - 在同一个 Linux 目录中有数百或数千个文件是否可以(性能方面)?

filesystems - 扩展属性存储在哪里?

java - 对于 (字符串 s : letters) {JAVA} How is this in php? 对于 ($string_l1 : $array){PHP}?

Java - ListIterator 实现细节

java - 使用 Iterator 从 HashMap 返回对象

c++ - 函数调用给我错误表达式必须有类类型

php - 使用 XSL 和 Php 将 XML 数据转换为 HTML : only printing xml tags without any formatting

PHP 没有收到单选按钮的值

php - 在浏览器中显示第一行的最后一个条目