PHP 日本大会 2024

DirectoryIterator::__construct

(PHP 5, PHP 7, PHP 8)

DirectoryIterator::__construct从路径构造一个新的目录迭代器

描述

public DirectoryIterator::__construct(string $directory)

从路径构造一个新的目录迭代器。

参数

directory

要遍历的目录的路径。

错误/异常

如果directory不存在,则抛出UnexpectedValueException

如果directory是空字符串,则抛出ValueError

变更日志

版本 描述
8.0.0 现在如果directory是空字符串,则抛出ValueError;之前它抛出的是RuntimeException

范例

示例 #1 DirectoryIterator::__construct() 示例

此示例将列出包含脚本的目录的内容。

<?php
$dir
= new DirectoryIterator(dirname(__FILE__));
foreach (
$dir as $fileinfo) {
if (!
$fileinfo->isDot()) {
var_dump($fileinfo->getFilename());
}
}
?>

添加注释

用户贡献注释 9 条注释

a dot lyskawa at nisza dot org
14 年前
这是一个多合一的 DirectoryIterator

<?php

/**
* 真正的递归目录迭代器
*/
class RRDI extends RecursiveIteratorIterator {
/**
* 创建真正的递归目录迭代器
* @param string $path
* @param int $flags
* @return DirectoryIterator
*/
public function __construct($path, $flags = 0) {
parent::__construct(new RecursiveDirectoryIterator($path, $flags));
}
}

/**
* 过滤后的真正的 RecursiveDirectoryIterator 类
* 只返回文件名与给定正则表达式匹配的项
*/
class AdvancedDirectoryIterator extends FilterIterator {
/**
* 正则表达式存储
* @var string
*/
private $regex;
/**
* 创建新的 AdvancedDirectoryIterator
* @param string $path, 前缀为 '-R ' 表示递归,后缀为 /[通配符] 表示匹配
* @param int $flags
* @return DirectoryIterator
*/
public function __construct($path, $flags = 0) {
if (
strpos($path, '-R ') === 0) { $recursive = true; $path = substr($path, 3); }
if (
preg_match('~/?([^/]*\*[^/]*)$~', $path, $matches)) { // 在文件名中匹配通配符
$path = substr($path, 0, -strlen($matches[1]) - 1); // 从路径中去除通配符部分
$this->regex = '~^' . str_replace('*', '.*', str_replace('.', '\.', $matches[1])) . '$~'; // 将通配符转换为正则表达式
if (!$path) $path = '.'; // 如果没有给出路径,我们假设为 CWD
}
parent::__construct($recursive ? new RRDI($path, $flags) : new DirectoryIterator($path));
}
/**
* 检查当前文件名中的正则表达式,如果没有指定正则表达式则匹配所有
* @return bool
*/
public function accept() { // FilterIterator 方法
return $this->regex === null ? true : preg_match($this->regex, $this->getInnerIterator()->getFilename());
}
}

?>

一些例子

<?php

/* @var $i DirectoryIterator */

foreach (new AdvancedDirectoryIterator('.') as $i) echo $i->getPathname() . '<br/>';
// 将输出 CWD 中的所有文件和目录

foreach (new AdvancedDirectoryIterator('-R *.php') as $i) echo $i->getPathname() . '<br/>';
// 将输出 CWD 和所有子目录中的所有 php 文件

foreach (new AdvancedDirectoryIterator('-R js/jquery-*.js') as $i) echo $i->getPathname() . '<br/>';
// 将输出 js 目录中的所有 jQuery 版本,如果 js 目录不存在则抛出异常

?>

很酷,对吧? :)
kendsnyder at gmail dot com
16 年前
不要将 DirectoryIterator 对象存储起来以供以后使用;当您存储超过操作系统限制(通常为 256 或 1024)数量的对象时,您将收到“打开的文件过多”的错误。

例如,如果目录中有太多文件,这将产生错误

<?php
$files
= array();
foreach (new
DirectoryIterator('myDir') as $file) {
$files[] = $file;
}
?>

据推测,这种方法也很耗内存。
goran at extensionsforjoomla dot com
17年前
我需要使用正则表达式匹配目录树中的文件名。代码基于Marcus Börger的DirectoryTreeIterator类 http://cvs.php.net/viewvc.cgi/php-src/ext/spl/examples/ 和他在2007年PHP魁北克会议上关于面向对象PHP的入门讲座中的示例 http://talks.somabo.de/
<?php
class KeyFilter extends FilterIterator
{
private
$_rx;

function
__construct(Iterator $it, $regex)
{
parent::__construct($it);
$this->_rx= $regex;
}

function
accept()
{
return
ereg($this->_rx,$this->getInnerIterator()->key());
}

protected function
__clone() {
return
false;
}
}

class
DirMach extends KeyFilter
{
function
__construct($path , $regex)
{
parent::__construct(
new
DirectoryTreeIterator($path), $regex);
}

function
current()
{
return
parent::key();
}

function
key()
{
return
parent::key();
}
}

class
DirectoryTreeIterator extends RecursiveIteratorIterator
{
/** 从路径构造。
* @param $path 要迭代的目录
*/
function __construct($path)
{
try {
parent::__construct(
new
RecursiveCachingIterator(
new
RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME
),
CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD
),
parent::SELF_FIRST
);
} catch(
Exception $e) {
echo
$e->getMessage();
exit;
}
}

/** @return 使用ASCII图形作为前缀的当前元素
*/
function current()
{
if (
$this->hasChildren())
$this->next();
return
$this->key();
}

/** 聚合内部迭代器
*/
function __call($func, $params)
{
return
call_user_func_array(array($this->getSubIterator(), $func), $params);
}
}
$PathToSearch = 'path_to_search';
$regex = 'regular_expression';
$FileList = new DirMach($PathToSearch, $regex);
foreach (
$FileList as $file) {
$match[] = $file;
}
echo
'<pre>';
var_dump($match);
echo
'</pre>';
?>
ahmad dot mayahi at gmail dot com
4年前
许多开发者混淆了DirectoryIterator和FilesystemIterator,它们之间有一些细微的差别,我将在这里列出。

DirectoryIterator
* 包括路径中的"."和".."
* 数字键。
* 路径不包含在值中。
* 无可用配置。
* 将元素存储到数组中时,需要使用"clone"。

示例
<?php
$files
= [];
foreach (
$dir as $key => $item) {
echo
$key.PHP_EOL; // 键是一个数字
$files[] = $item;
}

echo
$files[0]->getFilename(); // 此处不会发生任何事情,需要在foreach循环内使用clone $item

?>

FilesystemIterator
* 跳过点文件。
* 路径名用作键和值。
* 可配置。
* 使用SplFileInfo存储文件。

"FilesystemIterator"是DirectoryIterator的增强版,我更喜欢使用它而不是DirectoryIterator。
h.man
3年前
RecursiveDirectoryIterator似乎会关闭当前打开的文件句柄。使用它后,会给出"PHP Warning: fwrite(): supplied resource is not a valid stream resource in..."警告…
cmanley at example dot com
5年前
注意,DirectoryIterator在每次迭代时返回对自身的引用,而不是像人们最初假设的那样返回一个新的唯一的SplFileInfo对象。
如果您想将迭代结果推入数组以便稍后处理,则了解这一点非常重要。
如果您这样做,则数组中的所有条目都将是具有相同内部状态(很可能无效 - 请参见valid()方法)的相同DirectoryIterator对象,这可能不是您想要的。
因此,如果您确实想将迭代结果存储在数组中,则必须首先将它们转换为纯字符串或新的SplFileInfo对象。

$todo = [];
foreach (new DirectoryIterator('/some/dir') as $entry) {
if (!$entry->isFile()) {
continue;
}
#$todo []= $entry; # 不要这样做!
$todo []= new SplFileInfo($entry->getFilename()); # 这样做!
#$todo []= $entry->getFilename(); # 或者如果您只对文件名感兴趣,则这样做。
}
pcdinh at phpvietnam dot net
17年前
我需要递归遍历目录树并获取所有子目录路径,并编写了一个代码片段来执行此操作。

<?php
$path
= "D:\webroot\phpvietnamcms";
foreach (new
RecursiveIteratorIterator(
new
RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME), RecursiveIteratorIterator::CHILD_FIRST) as $file => $info) {
if (
$info->isDir())
{
echo
$file."<br />";
}
}

?>
springub at northclick dot de
17年前
udvig dot ericson at gmail dot com
2006年7月29日 07:48

回复下方udvig的评论。此示例是错误的,以下是正确的示例。

<?php
$dir
= new DirectoryIterator("/tmp");
foreach (
$dir as $file) {
if (
$file->isDot()) {
continue;
}
echo
$file->getFilename() . "\n";
}
?>
fernandobassani at gmail dot com
18年前
我们现在可以替换列出目录内容的旧式方法!

旧方法
<?php
if ($handle = opendir('/home/fernando/temp')) {
while (
false !== ($file = readdir($handle))) {
if (
$file != "." && $file != "..") {
print
"$file <br />";
}
}
closedir($handle);
}
?>

新方法
<?php
$dir
= new DirectoryIterator('/home/fernando/temp');
while(
$dir->valid()) {
if(!
$dir->isDot()) {
print
$dir->current()."<br />";
}
$dir->next();
}
?>
To Top