使用以下代码段以递归方式映射当前目录的内容:
$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 - 为返回的每个目录添加斜杠。
我知道我可以通过简单地做到:
foreach ($files as $key => $value)
{
$files[$key] .= (is_dir($value) ? '/' : '');
}
但这需要(不必要地?)多次击中磁盘。我正在寻找一种快速确定路径是目录还是常规文件的方法,结束斜杠似乎是理想的解决方案。
我打算用这个来遍历数十个(如果不是数百个)数千个文件,因此性能至关重要。
加分问题:有没有办法只获取目录(递归)?
答案 0 :(得分:4)
您可以创建自己的GlobMarkIterator
优势:
GLOB_MARK
array_map
与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());
}
}
编辑..如果您不关心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()) ."/";
}
}
答案 1 :(得分:1)
这是我迄今为止的最大努力:
$files = new RecursiveIteratorIterator
(
new RecursiveDirectoryIterator
(
str_replace('\\', '/', realpath('./')),
FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS
),
RecursiveIteratorIterator::LEAVES_ONLY
);
$files = array_keys(iterator_to_array($files));
$folders = array();
/*
foreach ($files as $key => $value) // not needed anymore
{
$files[$key] .= (is_dir($value) === true) ? '/' : '';
}
*/
$files = array_flip($files);
foreach ($files as $key => $value)
{
$folder = dirname($key) . '/'; // doesn't issue a stat call
if (array_key_exists($folder, $folders) !== true)
{
$folders[$folder] = 0;
}
$folders[$folder] += $files[$key] = sprintf('%u', filesize($key));
}
我可以将$folders
数组与$files
数组合并,以准确地回答这个问题,但区分其中一个恰好是我的主要目标,所以没有必要这样做。