我想获得所有子目录的列表,下面的代码可以工作,除非我对某些文件夹具有只读权限。
在下面的问题中,它显示了如何使用RecursiveDirectoryTerator跳过目录我可以让RecursiveDirectoryTerator跳过不可读的目录吗?然而,我的代码在这里略有不同,我无法解决这个问题。
$path = 'www/';
foreach (new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path,RecursiveDirectoryIterator::KEY_AS_PATHNAME),
RecursiveIteratorIterator::CHILD_FIRST) as $file => $info)
{
if ($info->isDir())
{
echo $file . '<br>';
}
}
我得到错误
Uncaught exception 'UnexpectedValueException' with message 'RecursiveDirectoryIterator::__construct(../../www/special): failed to open dir: Permission denied'
我试着用另一个问题中被接受的答案来代替它。
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator("."),
RecursiveIteratorIterator::LEAVES_ONLY,
RecursiveIteratorIterator::CATCH_GET_CHILD);
然而,这段代码不会像我想要的那样给我一个www内所有目录的列表,我在哪里出错了?
简介
代码的主要问题是使用CHILD_FIRST
来自PHP-DOC-
可选模式。可能的值为
- RecursiveIteratorIterator::LEAVES_ONLY-默认值。仅列出迭代中的叶子
- RecursiveIteratorIterator::SELF_FIRST-列出迭代中的叶子和父代,父代位于第一位
- RecursiveIteratorIterator::CHILD_FIRST-列出迭代中的叶子和父代,叶子在前
您应该使用SELF_FIRST
,以便包含当前目录。您还忘记添加可选参数RecursiveIteratorIterator::CATCH_GET_CHILD
来自PHP-DOC-
可选标志。可能的值是RecursiveIteratorIterator::CATCH_GET_CHILD,然后它将忽略在对RecursiveITeratorIterar::getChildren((的调用中引发的异常。
您的代码被修改
foreach (new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path,RecursiveDirectoryIterator::KEY_AS_PATHNAME),
RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD) as $file => $info)
{
if ($info->isDir())
{
echo $file . '<br>';
}
}
您真的想要CHILD_FIRST
如果你真的想维护CHILD_FIRST
结构,那么我建议你使用ReadableDirectoryIterator
示例
foreach ( new RecursiveIteratorIterator(
new ReadableDirectoryIterator($path),RecursiveIteratorIterator::CHILD_FIRST) as $file ) {
echo $file . '<br>';
}
分类使用
class ReadableDirectoryIterator extends RecursiveFilterIterator {
function __construct($path) {
if (!$path instanceof RecursiveDirectoryIterator) {
if (! is_readable($path) || ! is_dir($path))
throw new InvalidArgumentException("$path is not a valid directory or not readable");
$path = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
}
parent::__construct($path);
}
public function accept() {
return $this->current()->isReadable() && $this->current()->isDir();
}
}
我已经设置了以下目录结构:
/
test.php <-- the test script
www/
test1/ <-- permissions = 000
file1
test2/
file2
file3
我运行了以下代码(我添加了SKIP_DOTS
标志以跳过.
和..
btw(:
$i = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator("www", FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::LEAVES_ONLY,
RecursiveIteratorIterator::CATCH_GET_CHILD
);
print_r(iterator_to_array($i));
它输出以下内容:
Array
(
[www/test2/file2] => SplFileInfo Object
(
[pathName:SplFileInfo:private] => www/test2/file2
[fileName:SplFileInfo:private] => file2
)
[www/file3] => SplFileInfo Object
(
[pathName:SplFileInfo:private] => www/file3
[fileName:SplFileInfo:private] => file3
)
)
这是意料之中的事。
更新
添加了您在原始示例中使用的标志(尽管我认为这些都是默认的(:
foreach (new RecursiveIteratorIterator(
new RecursiveDirectoryIterator("www", FilesystemIterator::SKIP_DOTS | FilesystemIterator::KEY_AS_PATHNAME),
RecursiveIteratorIterator::LEAVES_ONLY,
RecursiveIteratorIterator::CATCH_GET_CHILD | RecursiveIteratorIterator::CHILD_FIRST
) as $file => $info) {
echo $file, "n";
print_r($info);
if ($info->isDir()) {
echo $file . '<br>';
}
}
输出:
www/test2/file2
SplFileInfo Object
(
[pathName:SplFileInfo:private] => www/test2/file2
[fileName:SplFileInfo:private] => file2
)
www/file3
SplFileInfo Object
(
[pathName:SplFileInfo:private] => www/file3
[fileName:SplFileInfo:private] => file3
)
function dirScan($dir, $fullpath = false){
$ignore = array(".","..");
if (isset($dir) && is_readable($dir)){
$dlist = array();
$dir = realpath($dir);
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir,RecursiveDirectoryIterator::KEY_AS_PATHNAME),RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD);
foreach($objects as $entry){
if(!in_array(basename($entry), $ignore)){
if (!$fullpath){
$entry = str_replace($dir, '', $entry);
}
$dlist[] = $entry;
}
}
return $dlist;
}
}
此代码100%有效。。。
您只需使用此功能即可扫描所需目录或驱动器中的文件和文件夹。您只需要将所需目录的路径传递到函数中。该功能的第二个参数是显示扫描文件和文件夹的完整路径。第二个参数的值为False表示不显示完整路径。
数组$ignore用于从列表中排除任何所需的文件名或文件夹名。
函数返回包含文件和文件夹列表的数组。
此函数跳过递归时无法读取的文件和文件夹。
<?php
$path = "D:/Movies";
$directory_iterator = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME);
$files = new RecursiveIteratorIterator($directory_iterator,
RecursiveIteratorIterator::SELF_FIRST,
RecursiveIteratorIterator::CATCH_GET_CHILD);
try {
foreach( $files as $fullFileName => $file) {
$path_parts = pathinfo($fullFileName);
if(is_file($fullFileName)){
$path_parts = pathinfo($fullFileName);
$fileName[] = $path_parts['filename'];
$extensionName[] = $path_parts['extension'];
$dirName[] = $path_parts['dirname'];
$baseName[] = $path_parts['basename'];
$fullpath[] = $fullFileName;
}
}
foreach ($fullpath as $filles){
echo $filles;
echo "</br>";
}
}
catch (UnexpectedValueException $e) {
printf("Directory [%s] contained a directory we can not recurse into", $directory);
}
?>
glob函数会自动跳过读取错误,并且应该会稍微简化代码。
如果你得到了未处理的异常,为什么不把代码放在try块中,当它不能读取目录时,用一个异常捕获块来捕获错误?只是一个简单的建议,通过查看您的代码和您的问题。在PHP中可能有一种更简洁的方法。
如果要返回不可读的目录名,则需要使用SELF_FIRST
常量。当您执行CHILD_FIRST
时,它试图进入目录,但失败了,并且不包括当前目录名。
$path = 'testing';
$directory_iterator = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME);
$iterator = new RecursiveIteratorIterator($directory_iterator,
RecursiveIteratorIterator::SELF_FIRST,
RecursiveIteratorIterator::CATCH_GET_CHILD);
foreach ($iterator as $file => $info) {
if ($info->isDir()) {
echo $file . "n";
}
}
尝试捕获UnexpectedValueException怎么样。也许您甚至可以检查该错误的唯一异常代码。否则,您可以解析异常消息中的"权限被拒绝"。
我建议检查http://php.net/manual/de/class.unexpectedvalueexception.php