rewinddir() 函数用于将目录句柄的指针重置到目录的开头。这使得可以重新读取目录内容,而不需要关闭并重新打开目录句柄。
当使用 readdir() 函数遍历目录后,目录指针会指向末尾。如果想再次遍历同一个目录,可以使用 rewinddir() 将指针重置到开头,然后再次使用 readdir() 读取。
rewinddir(?resource $dir_handle = null): void
| 参数 | 描述 |
|---|---|
| dir_handle |
可选。由 如果省略此参数或设置为 从 PHP 8.0.0 开始,此参数可以为 null。 |
rewinddir() 函数没有返回值(返回 void)。
<?php
// 打开目录
$dir = "/tmp";
$handle = opendir($dir);
if ($handle) {
echo "第一次遍历目录内容:<br>";
$count1 = 0;
// 读取前3个条目
while (false !== ($entry = readdir($handle)) && $count1 < 3) {
echo $entry . "<br>";
$count1++;
}
echo "<br>只显示了前 $count1 个条目<br><br>";
// 重置目录指针
rewinddir($handle);
echo "已使用 rewinddir() 重置指针<br><br>";
echo "第二次遍历所有目录内容:<br>";
$count2 = 0;
while (false !== ($entry = readdir($handle))) {
echo $entry . "<br>";
$count2++;
}
echo "<br>总计 $count2 个条目<br>";
// 关闭目录句柄
closedir($handle);
} else {
echo "无法打开目录: $dir";
}
?>
<?php
/**
* 演示多次使用 rewinddir() 重新读取目录内容
*/
function demonstrateRewinddir($directory) {
$handle = opendir($directory);
if (!$handle) {
return "无法打开目录: $directory";
}
$output = "目录: $directory<br><br>";
// 第一次读取:获取所有文件
$allFiles = [];
while (false !== ($entry = readdir($handle))) {
if ($entry !== '.' && $entry !== '..') {
$allFiles[] = $entry;
}
}
$output .= "第一次读取: 找到 " . count($allFiles) . " 个文件/目录<br>";
// 重置指针
rewinddir($handle);
$output .= "已重置指针<br><br>";
// 第二次读取:只获取目录
$directories = [];
while (false !== ($entry = readdir($handle))) {
if ($entry !== '.' && $entry !== '..') {
$fullPath = $directory . '/' . $entry;
if (is_dir($fullPath)) {
$directories[] = $entry;
}
}
}
$output .= "第二次读取: 找到 " . count($directories) . " 个子目录<br>";
// 再次重置指针
rewinddir($handle);
$output .= "再次重置指针<br><br>";
// 第三次读取:只获取特定扩展名的文件
$phpFiles = [];
while (false !== ($entry = readdir($handle))) {
if ($entry !== '.' && $entry !== '..') {
$fullPath = $directory . '/' . $entry;
if (is_file($fullPath) && pathinfo($entry, PATHINFO_EXTENSION) === 'php') {
$phpFiles[] = $entry;
}
}
}
$output .= "第三次读取: 找到 " . count($phpFiles) . " 个PHP文件<br><br>";
// 显示详细结果
$output .= "详细结果:<br>";
$output .= "所有文件/目录: " . implode(', ', $allFiles) . "<br>";
$output .= "子目录: " . implode(', ', $directories) . "<br>";
$output .= "PHP文件: " . implode(', ', $phpFiles) . "<br>";
closedir($handle);
return $output;
}
// 使用示例
echo demonstrateRewinddir("/tmp");
?>
<?php
/**
* 使用 rewinddir() 实现目录内容的分页显示
* @param string $directory 目录路径
* @param int $page 当前页码
* @param int $perPage 每页显示数量
* @return array 分页数据
*/
function paginateDirectory($directory, $page = 1, $perPage = 10) {
$handle = opendir($directory);
if (!$handle) {
return ['error' => "无法打开目录: $directory"];
}
$allEntries = [];
// 第一次遍历:获取所有条目(排除 . 和 ..)
while (false !== ($entry = readdir($handle))) {
if ($entry !== '.' && $entry !== '..') {
$allEntries[] = $entry;
}
}
// 计算分页信息
$total = count($allEntries);
$totalPages = ceil($total / $perPage);
$page = max(1, min($page, $totalPages));
$offset = ($page - 1) * $perPage;
// 重置指针
rewinddir($handle);
// 跳过不需要的条目
$skipped = 0;
$currentEntries = [];
$currentIndex = 0;
while (false !== ($entry = readdir($handle))) {
if ($entry === '.' || $entry === '..') {
continue;
}
if ($skipped < $offset) {
$skipped++;
continue;
}
if (count($currentEntries) < $perPage) {
$currentEntries[] = $entry;
} else {
break;
}
$currentIndex++;
}
closedir($handle);
return [
'entries' => $currentEntries,
'page' => $page,
'perPage' => $perPage,
'total' => $total,
'totalPages' => $totalPages,
'hasPrevious' => $page > 1,
'hasNext' => $page < $totalPages
];
}
// 使用示例
$directory = "/tmp";
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$result = paginateDirectory($directory, $page, 5);
if (isset($result['error'])) {
echo $result['error'];
} else {
echo "目录内容 (第 {$result['page']} 页,共 {$result['totalPages']} 页):<br><br>";
foreach ($result['entries'] as $entry) {
echo "- $entry<br>";
}
echo "<br>";
echo "总计: {$result['total']} 个条目<br>";
// 分页导航
if ($result['hasPrevious']) {
echo "<a href='?page=" . ($result['page'] - 1) . "'>上一页</a> | ";
}
for ($i = 1; $i <= $result['totalPages']; $i++) {
if ($i == $result['page']) {
echo "<strong>$i</strong> ";
} else {
echo "<a href='?page=$i'>$i</a> ";
}
}
if ($result['hasNext']) {
echo "| <a href='?page=" . ($result['page'] + 1) . "'>下一页</a>";
}
}
?>
<?php
// 使用 dir() 函数返回的 Directory 对象
$dir = dir("/tmp");
if ($dir) {
echo "使用 Directory 对象的 rewind() 方法:<br><br>";
echo "第一次读取:<br>";
$count = 0;
while (false !== ($entry = $dir->read()) && $count < 5) {
echo $entry . "<br>";
$count++;
}
echo "<br>已读取 $count 个条目<br><br>";
// 使用 Directory 对象的 rewind() 方法
$dir->rewind();
echo "已调用 rewind() 方法重置指针<br><br>";
echo "第二次读取(所有条目):<br>";
$total = 0;
while (false !== ($entry = $dir->read())) {
echo $entry . "<br>";
$total++;
}
echo "<br>总计: $total 个条目<br>";
$dir->close();
} else {
echo "无法打开目录";
}
?>
<?php
/**
* 安全的目录遍历和重置函数
*/
function safelyRewindDirectory($directory) {
// 尝试打开目录
$handle = @opendir($directory);
if ($handle === false) {
$error = error_get_last();
return "错误: 无法打开目录 '$directory' - " . $error['message'];
}
try {
$results = [];
// 第一次遍历:获取文件统计
echo "第一次遍历 - 获取基本信息:<br>";
$fileCount = 0;
$dirCount = 0;
while (false !== ($entry = readdir($handle))) {
if ($entry === '.' || $entry === '..') {
continue;
}
$fullPath = $directory . DIRECTORY_SEPARATOR . $entry;
if (is_file($fullPath)) {
$fileCount++;
} elseif (is_dir($fullPath)) {
$dirCount++;
}
}
$results['first_pass'] = ['files' => $fileCount, 'directories' => $dirCount];
echo "文件: $fileCount, 目录: $dirCount<br><br>";
// 重置指针
if (!rewinddir($handle)) {
throw new Exception("无法重置目录指针");
}
echo "已成功重置目录指针<br><br>";
// 第二次遍历:获取详细文件列表
echo "第二次遍历 - 获取详细列表:<br>";
$details = [];
while (false !== ($entry = readdir($handle))) {
if ($entry === '.' || $entry === '..') {
continue;
}
$fullPath = $directory . DIRECTORY_SEPARATOR . $entry;
$details[] = [
'name' => $entry,
'type' => is_dir($fullPath) ? 'directory' : 'file',
'size' => is_file($fullPath) ? filesize($fullPath) : null,
'modified' => date('Y-m-d H:i:s', filemtime($fullPath))
];
}
$results['second_pass'] = $details;
// 输出详细信息
foreach ($details as $item) {
$size = $item['size'] ? formatBytes($item['size']) : '-';
echo "{$item['name']} ({$item['type']}, {$size}, {$item['modified']})<br>";
}
return $results;
} catch (Exception $e) {
return "错误: " . $e->getMessage();
} finally {
// 确保关闭目录句柄
if ($handle && is_resource($handle)) {
closedir($handle);
echo "<br>目录句柄已关闭";
}
}
}
// 辅助函数:格式化字节大小
function formatBytes($bytes, $precision = 2) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
// 使用示例
$result = safelyRewindDirectory("/tmp");
if (is_string($result)) {
echo $result; // 显示错误信息
}
?>
<?php
/**
* 比较 rewinddir() 和关闭重新打开的性能
*/
function comparePerformance($directory, $iterations = 1000) {
$results = [];
// 方法1:使用 rewinddir()
$start1 = microtime(true);
$handle = opendir($directory);
if ($handle) {
for ($i = 0; $i < $iterations; $i++) {
while (false !== ($entry = readdir($handle))) {
// 模拟一些处理
strlen($entry);
}
rewinddir($handle);
}
closedir($handle);
}
$end1 = microtime(true);
$results['rewinddir'] = $end1 - $start1;
// 方法2:关闭并重新打开
$start2 = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$handle = opendir($directory);
if ($handle) {
while (false !== ($entry = readdir($handle))) {
// 模拟一些处理
strlen($entry);
}
closedir($handle);
}
}
$end2 = microtime(true);
$results['reopen'] = $end2 - $start2;
return $results;
}
// 运行性能测试(小规模测试)
echo "性能测试(100次迭代):<br>";
$performance = comparePerformance("/tmp", 100);
echo "使用 rewinddir(): " . round($performance['rewinddir'] * 1000, 2) . " 毫秒<br>";
echo "关闭并重新打开: " . round($performance['reopen'] * 1000, 2) . " 毫秒<br><br>";
$difference = $performance['reopen'] - $performance['rewinddir'];
$percentage = ($difference / $performance['rewinddir']) * 100;
echo "性能差异: " . round($difference * 1000, 2) . " 毫秒<br>";
echo "rewinddir() 比关闭重新打开快 " . round($percentage, 2) . "%";
?>
使用 rewinddir() 可以方便地实现目录内容的分页,避免多次打开目录的开销。
当需要对同一个目录进行多次不同的处理(如统计、过滤、排序)时,使用 rewinddir() 可以提高效率。
在开发过程中,可以使用 rewinddir() 重置指针,多次测试不同的目录处理逻辑。
在资源受限的环境中,使用 rewinddir() 避免频繁的目录打开/关闭操作,节省系统资源。