dir

(PHP 4, PHP 5, PHP 7, PHP 8)

dir返回 Directory 类的一个实例

描述

dir(string $directory, ?resource $context = null): Directory|false

一种伪面向对象机制,用于读取目录。打开给定的 directory

参数

directory

要打开的目录

context

一个 上下文流 resource.

返回值

返回 Directory 的一个实例,或在发生错误时返回 false

变更日志

版本 描述
8.0.0 context 现在可以为空。

范例

范例 #1 dir() 范例

请注意下面的示例中检查 Directory::read() 返回值的时尚方式。我们明确地测试返回值是否与 (等于且类型相同 - 参见 比较运算符 获取更多信息) false 相同,因为否则,任何名称评估为 false 的目录条目将停止循环。

<?php
$d
= dir("/etc/php5");
echo
"Handle: " . $d->handle . "\n";
echo
"Path: " . $d->path . "\n";
while (
false !== ($entry = $d->read())) {
echo
$entry."\n";
}
$d->close();
?>

上面的示例将输出类似于以下的内容

Handle: Resource id #2
Path: /etc/php5
.
..
apache
cgi
cli

备注

注意:

read 方法返回目录条目的顺序是系统相关的。

添加备注

用户贡献的备注 20 个备注

8
synnus at gmail dot com
3 年前
<?php

// 简单地使用 FilesystemIterator
// 可以跳过点和双点
// 并将其用在数组中
// new FilesystemIterator( PATH , OPTIONS ) : array

$array_file_list = new FilesystemIterator( PATH_ROOT . 'folder/', FilesystemIterator::SKIP_DOTS );

?>
9
manuel at buschmanuel dot de
16 年前
这是我如何进行有效递归目录列出的解决方案。

玩得开心。

<?php

/**
* 使用示例:
*/
$d = new RecDir("/etc/",false);
echo
"Path: " . $d->getRootPath() . "\n";
while (
false !== ($entry = $d->read())) {
echo
$entry."\n";
}
$d->close();

class
RecDir
{
protected
$currentPath;
protected
$slash;
protected
$rootPath;
protected
$recursiveTree;

function
__construct($rootPath,$win=false)
{
switch(
$win)
{
case
true:
$this->slash = '\\';
break;
default:
$this->slash = '/';
}
$this->rootPath = $rootPath;
$this->currentPath = $rootPath;
$this->recursiveTree = array(dir($this->rootPath));
$this->rewind();
}

function
__destruct()
{
$this->close();
}

public function
close()
{
while(
true === ($d = array_pop($this->recursiveTree)))
{
$d->close();
}
}

public function
closeChildren()
{
while(
count($this->recursiveTree)>1 && false !== ($d = array_pop($this->recursiveTree)))
{
$d->close();
return
true;
}
return
false;
}

public function
getRootPath()
{
if(isset(
$this->rootPath))
{
return
$this->rootPath;
}
return
false;
}

public function
getCurrentPath()
{
if(isset(
$this->currentPath))
{
return
$this->currentPath;
}
return
false;
}

public function
read()
{
while(
count($this->recursiveTree)>0)
{
$d = end($this->recursiveTree);
if((
false !== ($entry = $d->read())))
{
if(
$entry!='.' && $entry!='..')
{
$path = $d->path.$entry;

if(
is_file($path))
{
return
$path;
}
elseif(
is_dir($path.$this->slash))
{
$this->currentPath = $path.$this->slash;
if(
$child = @dir($path.$this->slash))
{
$this->recursiveTree[] = $child;
}
}
}
}
else
{
array_pop($this->recursiveTree)->close();
}
}
return
false;
}

public function
rewind()
{
$this->closeChildren();
$this->rewindCurrent();
}

public function
rewindCurrent()
{
return
end($this->recursiveTree)->rewind();
}
}
?>
4
samuel dot l at mushicrew dot com
18 年前
请注意,在使用 PHP 5.x 的 Windows 上,dir 对象将使用非 Unicode 程序的默认编码。

因此,如果您有一个使用当前默认编码不支持的字符命名的文件,dir->read() 方法将返回错误的条目。

<?php
/*
** 此脚本与一个以当前默认编码不支持的字符命名的文件位于同一目录中。**
*/
$d = dir("./");
while(
false !== ($e = $d->read()))
echo
$e . '<br/>';
?>

这将为每个不支持的字符打印一个“?”,而不是正确的文件名。因此,如果您在枚举后立即使用 is_file/is_dir 检查,请注意这一点。
6
fordiman at gmail dot com
18 年前
这个挺不错的。在为在我的庞大音乐收藏中寻找 .jpg 文件而感到沮丧之后(PHP 会耗尽内存),我认为应该有一个 preg_ls 函数。

function preg_ls ($path=".", $rec=false, $pat="/.*/") {
// 它将被重复使用,确保我们编译它以提高速度。
$pat=preg_replace("|(/.*/[^S]*)|s", "\\1S", $pat);
// 从路径中删除尾部斜杠
while (substr($path,-1,1)=="/") $path=substr($path,0,-1);
// 同时,确保 $path 是一个目录并修复任何错误
if (!is_dir($path)) $path=dirname($path);
// 断言 $rec 的真值或假值,允许任何标量表示真值
if ($rec!==true) $rec=false;
// 获取目录句柄
$d=dir($path);
// 初始化输出数组
$ret=Array();
// 循环,读取直到没有更多可读取的内容
while (false!==($e=$d->read())) {
// 忽略父链接和自身链接
if (($e==".")||($e=="..")) continue;
// 如果我们正在递归工作,并且它是一个目录,则获取并合并
if ($rec && is_dir($path."/".$e)) {
$ret=array_merge($ret,preg_ls($path."/".$e,$rec,$pat));
continue;
}
// 如果它不匹配,则排除它
if (!preg_match($pat,$e)) continue;
// 在所有其他情况下,将其添加到输出数组中
$ret[]=$path."/".$e;
}
// 最后,返回数组
return $ret;
}

仅仅 18 行代码,还不错吧?

使用示例

foreach (preg_ls("/etc/X11", true, "/.*\.conf/i") as $file) echo $file."\n";

输出

/etc/X11/xkb/README.config
/etc/X11/xorg.conf-vesa
/etc/X11/xorg.conf~
/etc/X11/gui.conf
/etc/X11/xorg.conf
/etc/X11/xorg.conf-fbdev
1
synnus at gmail dot com
2 年前
<?php

/*
新的递归 PHP8
使用 FilesystemIterator 生成数组路径
*/

$recurcive_path = [];
rdir(path, $recurcive_path);
var_dump($recurcive_path);

function
rdir(string $path, array &$recurcive_path): string
{
if (
$path != '') {
$recurcive_path[] = $path;
$array_list = iterator_to_array(new FilesystemIterator($path, FilesystemIterator::SKIP_DOTS));
foreach (
$array_list as $name) {
$pathname = $name->getpathname();
if(
is_dir($pathname) && $name->getfilename()[0] != '.'){
$path = rdir($pathname,$recurcive_path);
}
}
return
$path;
}
return
'';
}

?>
2
synnus at gmail dot com
8 年前
<?php
// 最佳的小递归 dir()
// $entry[0]!='.' <=== 特别是为了保护以点 '.' 作为第一个字符的 FTP 文件
// 返回值:
// download\file\text\test.txt;
// download\video\anime\test.mp4;
// download\video\film\test2.mkv;

echo rdir('download'); // 从 \\download 开始目录

function rdir($path='',$k='') {
$d = dir($path);
while (
false !== ($entry = $d->read())) {
if(
$entry[0]!='.') {
if(
is_dir($path . '\\' . $entry)) {
$k = rdir($k,$path . '\\' . $entry);
}
else {
$k .= $path . '\\' . $entry . "; \n" ;
}

}
}
$d->close();
return
$k;
}

?>
3
匿名
18 年前
关于 samuel 关于 dir() 函数不支持 Unicode 的评论,关键在于编码。该函数在内部不会将 Unicode 字符转换为问号 (?),就像我最初认为的那样。如果你只是尝试以 UTF-8 编码输出它们,它们就会正常显示。
1
GUILLE@GARGANO
13 年前
获取 http://www.example.com/directory 的目录

<?php
function remotedir($dir)
{
$dir = str_replace(" ", "%20", html_entity_decode($dir));
if ((
$rh = fopen($dir, 'rb')) === FALSE) { return false; }
$i = 0;
while (!
feof($rh)) {
$archivos = fgetss($rh);
$directorio[$i++] = trim( substr($archivos,1,strpos($archivos," ",1)) );
}
fclose($rh);
return
$directorio;
}
?>
1
synnus at gmail dot com
6 年前
<?php

// 使用 $entry[0] != '.' 来检测是否是 '..' 或 '.'

$d = dir('.');
echo
"指针 : " . $d->handle . "<br/>\n";
echo
"路径 : " . $d->path . "<br/>\n";
while (
false !== ($entry = $d->read())) {

if(
$entry[0] != '.' ) {
echo .
"<br/>\n";
}

}
$d->close()

?>
0
Alex A.
13 年前
<?PHP
/*简单、美观的递归函数用于打印目录。
0
cf at chronofish dot com
17 年前
据我所知,在 Windows 系统上,dir 类不是目录的实时镜像。当类实例化时,它会拍摄目录的快照,然后迭代器使用该快照。

我可能错了,但当我运行两个进程,它们都查看目录是否存在,然后在一些处理完成后删除目录时,一个进程的删除不会影响另一个进程的迭代。

为了解决这个问题,我在进行处理之前检查文件是否存在。

$d = dir($dataDir);
while (false !== ($entry = $d->read()))
if ($entry != '..' && $entry != '.' && file_exists("$dataDir\\$entry"))
{
// 处理
}
$d->close();

我将此作为批处理运行,可以多次激活它以并行处理目录列表。

-CF
0
Anton Backer
18 年前
我修改了下面的脚本,以获取任何目录的叶文件夹(没有子文件夹的文件夹)。

注意:这不会返回作为参数传入的文件夹,即使它没有子文件夹。

<?php
function get_leaf_dirs($dir) {
$array = array();
$d = dir($dir);
while (
false !== ($entry = $d->read())) {
if(
$entry!='.' && $entry!='..') {
$entry = $dir.'/'.$entry;
if(
is_dir($entry)) {
$subdirs = get_leaf_dirs($entry);
if (
$subdirs)
$array = array_merge($array, $subdirs);
else
$array[] = $entry;
}
}
}
$d->close();
return
$array;
}
?>
-1
thomas at hawkes dot ca
17 年前
使用 SPL,你可以递归地列出当前目录中的所有文件夹,如下所示

<?php
$it
= new RecursiveDirectoryIterator('./');

// RecursiveIteratorIterator 接受以下模式:
// LEAVES_ONLY = 0 (默认)
// SELF_FIRST = 1
// CHILD_FIRST = 2
foreach (new RecursiveIteratorIterator($it, 2) as $path) {

if (
$path->isDir()) {

echo
"$path\n";

}

}
?>
-2
done_to_death at example dot com
17 年前
function directoryList($start,$win32=false){
if($win32){
$slash="\\";
}else{
$slash="/";
}
$basename = pathinfo($start);
$basename = $basename['basename'];
$ls=array();
$dir = dir($start);
while($item = $dir->read()){
if(is_dir($start.$slash.$item)&& $item!="." && $item!=".."){
$ls[$basename][]=directoryList($start.$slash.$item,$win32);
}else{
if($item!="."&&$item!=".."){
$ls[$basename][]=$item;
}
}
}
return $ls;
}

$path = pathinfo(__FILE__);
$ls = directoryList($path['dirname'], true);
-3
alex at snet-group dot org
17 年前
恕我直言,这对于较少的错误来说效果最好;)

function get_leaf_dirs($dir)
{
$array = array();
$d = @dir($dir);
if($d)
{
while (false !== ($entry = $d->read()))
{
if($entry!='.' && $entry!='..')
{
$entry = $dir.'/'.$entry;
if(is_dir($entry))
{
$subdirs = get_leaf_dirs($entry);
if ($subdirs)
$array = array_merge($array, $subdirs);
else
$array[] = $entry;
}
}
}
$d->close();
}
return $array;
}
-3
emanueledelgrande at email dot it
14 年前
在创建自定义解决方案时,使用预定义的 PHP 常量来缩短代码并提高性能
https://php.net/manual/en/reserved.constants.php

例如,DIRECTORY_SEPARATOR 可以替换一个函数,在该函数中,您检查 PHP_OS 以设置目录分隔符是 "/" 还是 "\\"。

干杯。
-6
radar at frozenplague dot net
18 年前
关于 jaqb 关于 read_dir 函数的修正的帖子,如果人们希望列出此目录内的目录并将它们读入同一个数组中,我也有一个小小的修正。

<?
function read_dir($dir) {
$array = array();
$d = dir($dir);
while (false !== ($entry = $d->read())) {
if($entry!='.' && $entry!='..') {
$entry = $dir.'/'.$entry;
if(is_dir($entry)) {
$array[] = $entry;
$array = array_merge($array, read_dir($entry));
} else {
$array[] = $entry;
}
}
}
$d->close();
return $array;
}
?>
-4
http://www.rooftopsolutions.nl
17 年前
<?php

$i
= new RecursiveIteratorIterator(new RecursiveDirectoryIterator('.'));

?>

对我有用。
-6
sojka at online-forum dot net
15 年前
这就是我将递归目录存储到数组中的方式。

<?php
public static function getTreeFolders($sRootPath = UPLOAD_PATH_PROJECT, $iDepth = 0) {
$iDepth++;
$aDirs = array();
$oDir = dir($sRootPath);
while((
$sDir = $oDir->read()) !== false) {
if(
$sDir != '.' && $sDir != '..' && is_dir($sRootPath.$sDir)) {
$aDirs[$iDepth]['sName'][] = $sDir;
$aDirs[$iDepth]['aSub'][] = self::getTreeFolders($sRootPath.$sDir.'/',$iDepth);
}
}
$oDir->close();
return empty(
$aDirs) ? false : $aDirs;
}
?>
-6
fordiman at gmail dot com
18 年前
看到了叶目录部分……快速修改

function preg_ls ($path=".", $rec=false, $pat="/.*/") {
$pat=preg_replace ("|(/.*/[^S]*)|s", "\\1S", $pat);
while (substr ($path,-1,1) =="/") $path=substr ($path,0,-1);
if (!is_dir ($path) ) $path=dirname ($path);
if ($rec!==true) $rec=false;
$d=dir ($path);
$ret=Array ();
while (false!== ($e=$d->read () ) ) {
if ( ($e==".") || ($e=="..") ) continue;
if ($rec && is_dir ($path."/".$e) ) {
$ret=array_merge ($ret,preg_ls($path."/".$e,$rec,$pat));
continue;
}
if (!preg_match ($pat,$e) ) continue;
$ret[]=$path."/".$e;
}
return (empty ($ret) && preg_match ($pat,basename($path))) ? Array ($path."/") : $ret;
}

例子

foreach (preg_ls ("/usr/share/fluxbox", true, "/[LT]e[sa]/i") as $file) echo $file."\n";

输出

/usr/share/fluxbox/styles/Leaf/
/usr/share/fluxbox/styles/Clean
/usr/share/fluxbox/styles/Testing/
To Top