在使用PHP进行目录遍历操作时,readdir函数是常用的获取目录条目的方法,但不少开发者初次使用时会发现,遍历结果里总是会出现.和..这两个看起来没有实际意义的条目,这和目录系统的底层设计有直接关系。

readdir返回点号和双点号的原因
在类Unix系统和Windows系统的文件目录结构中,每个目录默认都会包含两个特殊的隐藏条目:
- .:表示当前目录本身,在路径解析时用于指代当前所在目录
- ..:表示上一级目录,在路径解析时用于指代当前目录的父目录
readdir函数的作用是读取目录句柄下的所有条目,并不会自动过滤这些系统默认存在的特殊条目,因此调用readdir遍历目录时,这两个条目会和其他普通文件、文件夹一起被返回。如果开发者没有做过滤处理,就可能会在后续逻辑中把这两个特殊条目当成普通文件或目录处理,引发不符合预期的问题。
手动过滤.与..的实现方法
过滤这两个特殊条目的核心逻辑是,在遍历到每个条目时,判断当前条目的名称是否为.或者..,如果是则跳过,否则执行后续业务逻辑。
基础过滤实现
以下是最基础的遍历并过滤示例:
<?php
$dirPath = './test_dir'; // 要遍历的目录路径
if (is_dir($dirPath)) {
$handle = opendir($dirPath);
if ($handle) {
while (($file = readdir($handle)) !== false) {
// 过滤点号和双点号
if ($file == '.' || $file == '..') {
continue;
}
// 处理普通条目
echo "遍历到条目:{$file}" . PHP_EOL;
}
closedir($handle);
}
}
?>
结合条目类型判断的过滤实现
如果需要在遍历时同时区分文件和目录,可以在过滤后进一步判断条目类型:
<?php
$dirPath = './test_dir';
if (is_dir($dirPath)) {
$handle = opendir($dirPath);
if ($handle) {
while (($file = readdir($handle)) !== false) {
if ($file == '.' || $file == '..') {
continue;
}
$fullPath = $dirPath . '/' . $file;
if (is_dir($fullPath)) {
echo "目录:{$file}" . PHP_EOL;
} else {
echo "文件:{$file}" . PHP_EOL;
}
}
closedir($handle);
}
}
?>
注意事项
- 过滤判断时需要注意字符串比较的准确性,不要使用松散比较导致误判,比如不要使用
==比较时引入其他类型转换问题,常规场景下直接使用==比较字符串是安全的,但如果有特殊需求可以使用===严格比较 - 如果遍历的目录路径是通过用户输入传递的,需要先对路径做安全校验,避免目录遍历漏洞
- 除了.和..之外,部分系统下可能还有其他的隐藏文件,比如以.开头的文件,如果有需要可以根据业务需求额外增加过滤规则
按照上述方式处理之后,就可以避免readdir返回的点号和双点号对业务逻辑造成干扰,让目录遍历的结果更符合实际开发需求。