PHP Conference Japan 2024

scandir

(PHP 5, PHP 7, PHP 8)

scandir列出指定路径内的文件和目录

描述

scandir(字符串 $directory, 整数 $sorting_order = SCANDIR_SORT_ASCENDING, ?资源 $context = null): 数组|false

返回来自 directory 的文件和目录的 数组

参数

directory

将要扫描的目录。

sorting_order

默认情况下,排序顺序为升序字母顺序。如果可选的 sorting_order 设置为 SCANDIR_SORT_DESCENDING,则排序顺序为降序字母顺序。如果将其设置为 SCANDIR_SORT_NONE,则结果为未排序。

context

有关 context 参数的说明,请参阅手册的 流部分

返回值

如果成功,则返回文件名 数组,如果失败则返回 false。如果 directory 不是目录,则返回布尔值 false,并生成级别为 E_WARNING 的错误。

变更日志

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

示例

示例 #1 一个简单的 scandir() 示例

<?php
$dir
= '/tmp';
$files1 = scandir($dir);
$files2 = scandir($dir, SCANDIR_SORT_DESCENDING);

print_r($files1);
print_r($files2);
?>

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

Array
(
    [0] => .
    [1] => ..
    [2] => bar.php
    [3] => foo.txt
    [4] => somedir
)
Array
(
    [0] => somedir
    [1] => foo.txt
    [2] => bar.php
    [3] => ..
    [4] => .
)

注释

提示

如果启用了 fopen 封装器,则 URL 可以用作此函数的文件名。有关如何指定文件名的更多详细信息,请参阅 fopen()。请参阅 支持的协议和封装器,以获取有关各个封装器具有的功能、用法说明以及它们可能提供的任何预定义变量的信息。

参见

  • opendir() - 打开目录句柄
  • readdir() - 从目录句柄读取条目
  • glob() - 查找与模式匹配的文件名
  • is_dir() - 判断文件名是否为目录
  • sort() - 按升序对数组排序

添加注释

用户贡献的注释 16 条注释

dwieeb at gmail dot com
12 年前
在 Linux 环境中轻松去除 scandir() 获取到的点

<?php
$directory
= '/path/to/my/directory';
$scanned_directory = array_diff(scandir($directory), array('..', '.'));
?>
mmda dot nl at gmail dot com
12 年前
这是我的 2 分钱。我想递归创建目录结构的数组。我想使用 foreach 轻松访问特定目录中的数据。我想出了以下方法

<?php
function dirToArray($dir) {

$result = array();

$cdir = scandir($dir);
foreach (
$cdir as $key => $value)
{
if (!
in_array($value,array(".","..")))
{
if (
is_dir($dir . DIRECTORY_SEPARATOR . $value))
{
$result[$value] = dirToArray($dir . DIRECTORY_SEPARATOR . $value);
}
else
{
$result[] = $value;
}
}
}

return
$result;
}
?>

输出
数组
(
[subdir1] => 数组
(
[0] => file1.txt
[subsubdir] => 数组
(
[0] => file2.txt
[1] => file3.txt
)
)
[subdir2] => 数组
(
[0] => file4.txt
}
)
info at remark dot no
6 年前
有人写道,可以使用 array_slice 快速删除目录条目“.”和“..”。但是,“-” 是一个有效的条目,它会出现在这些条目之前,因此 array_slice 会删除错误的条目。
kodlee at kodleeshare dot net
12 年前
我需要找到一种方法来获取目录和目录的所有子目录中所有文件的完整路径。
这是我的解决方案:递归函数!

<?php
function find_all_files($dir)
{
$root = scandir($dir);
foreach(
$root as $value)
{
if(
$value === '.' || $value === '..') {continue;}
if(
is_file("$dir/$value")) {$result[]="$dir/$value";continue;}
foreach(
find_all_files("$dir/$value") as $value)
{
$result[]=$value;
}
}
return
$result;
}
?>
gambit_642 AT hotmailDOTcom
10 年前
需要一些可以递归或非递归返回单个或多个目录内容的内容,
用于所有文件或指定的文件扩展名,这些文件扩展名将是
可从任何作用域或脚本轻松访问。

而且我想允许重载,因为有时我懒得传递所有参数。
<?php
class scanDir {
static private
$directories, $files, $ext_filter, $recursive;

// ----------------------------------------------------------------------------------------------
// scan(dirpath::string|array, extensions::string|array, recursive::true|false)
static public function scan(){
// 初始化默认值
self::$recursive = false;
self::$directories = array();
self::$files = array();
self::$ext_filter = false;

// 检查我们是否具有最小参数
if(!$args = func_get_args()){
die(
"必须提供路径字符串或路径字符串数组");
}
if(
gettype($args[0]) != "string" && gettype($args[0]) != "array"){
die(
"必须提供路径字符串或路径字符串数组");
}

// 检查是否为递归扫描 | 默认操作:无子目录
if(isset($args[2]) && $args[2] == true){self::$recursive = true;}

// 是否包含文件扩展名过滤器? | 默认操作:返回所有文件类型
if(isset($args[1])){
if(
gettype($args[1]) == "array"){self::$ext_filter = array_map('strtolower', $args[1]);}
else
if(
gettype($args[1]) == "string"){self::$ext_filter[] = strtolower($args[1]);}
}

// 获取路径
self::verifyPaths($args[0]);
return
self::$files;
}

static private function
verifyPaths($paths){
$path_errors = array();
if(
gettype($paths) == "string"){$paths = array($paths);}

foreach(
$paths as $path){
if(
is_dir($path)){
self::$directories[] = $path;
$dirContents = self::find_contents($path);
} else {
$path_errors[] = $path;
}
}

if(
$path_errors){echo "以下目录不存在<br />";die(var_dump($path_errors));}
}

// 这是我们扫描目录的方式
static private function find_contents($dir){
$result = array();
$root = scandir($dir);
foreach(
$root as $value){
if(
$value === '.' || $value === '..') {continue;}
if(
is_file($dir.DIRECTORY_SEPARATOR.$value)){
if(!
self::$ext_filter || in_array(strtolower(pathinfo($dir.DIRECTORY_SEPARATOR.$value, PATHINFO_EXTENSION)), self::$ext_filter)){
self::$files[] = $result[] = $dir.DIRECTORY_SEPARATOR.$value;
}
continue;
}
if(
self::$recursive){
foreach(
self::find_contents($dir.DIRECTORY_SEPARATOR.$value) as $value) {
self::$files[] = $result[] = $value;
}
}
}
// 递归搜索需要返回值
return $result;
}
}
?>

用法
scanDir::scan(path(s):string|array, [file_extensions:string|array], [subfolders?:true|false]);
<?php
// 扫描单个目录中的所有文件,不包含子目录
$files = scanDir::scan('D:\Websites\temp');

// 扫描多个目录中的所有文件,不包含子目录
$dirs = array(
'D:\folder';
'D:\folder2';
'C:\Other';
);
$files = scanDir::scan($dirs);

// 扫描多个目录中具有指定文件扩展名的文件,
// 不包含子目录
$files = scanDir::scan($dirs, "jpg");
// 或使用扩展名数组
$file_ext = array(
"jpg",
"bmp",
"png"
);
$files = scanDir::scan($dirs, $file_ext);

// 扫描多个目录中具有任何扩展名的文件,
// 包括递归子文件夹中的文件
$files = scanDir::scan($dirs, false, true);

// 多个目录,具有指定的扩展名,包括子目录文件
$files = scanDir::scan($dirs, $file_ext, true);
?>
[email protected]
10 年前
获取文件列表(不含点)的最快方法。
<?php
$files
= array_slice(scandir('/path/to/directory/'), 2);
[email protected]
5 年前
我如何解决“.” 和 “..” 的问题

$x = scandir(__DIR__); // 任何目录
foreach ($x as $key => $value) {
if ('.' !== $value && '..' !== $value){
echo $value;
}
}
简单易用
[email protected]
3 年前
一个简单的递归函数,用于列出目录中的所有文件和子目录


<?php
function listAllFiles($dir) {
$array = array_diff(scandir($dir), array('.', '..'));

foreach (
$array as &$item) {
$item = $dir . $item;
}
unset(
$item);
foreach (
$array as $item) {
if (
is_dir($item)) {
$array = array_merge($array, listAllFiles($item . DIRECTORY_SEPARATOR));
}
}
return
$array;
}
?>
[email protected]
19年前
增强版的scandir
当您需要过滤文件列表或仅列出这么多级别的子目录时...

<?php
function dirList($path="", $types=2, $levels=1, $aFilter=array()) {
// 返回指定文件/目录的数组
// 从 $path 开始搜索(默认为当前工作目录)
// 返回 $types:2 => 文件;1 => 目录;3 => 两者;
// $levels:1 => 只查看 $path;2 => $path 及其所有子级;
// 3 => $path、子级、孙级;0 => $path 及其所有子目录;
// 小于 0 => -$levels 的补集,或从 -$levels 开始的所有内容
// 例如 -1 => 除 $path 之外的所有内容;-2 => 除 $path + 子级之外的所有后代
// 其余参数是一个正则表达式数组(列表),用于对完整路径进行操作。
// 第一个字符(在 regExp 的 '/' 之前)'-' => 非。
// 第一个字符(在可能的 '-' 之后)'d' => 应用于目录名称
// 过滤器可以作为字符串数组或字符串列表传递
// 请注意,输出目录以 '*' 为前缀(在返回语句之前的行中完成)
$dS = DIRECTORY_SEPARATOR;
if (!(
$path = realpath($path?$path:getcwd()))) return array(); // 路径错误
// 下一行删除驱动器上的终止 \(在 PHP 上有效,因为 c: == c:\)。在 *nix 上可以吗?
if (substr($path,-1)==$dS) $path = substr($path,0,-1);
if (
is_null($types)) $types = 2;
if (
is_null($levels)) $levels = 1;
if (
is_null($aFilter)) $aFilter=array();

// 最后一个参数可以作为列表或数组传递
$aFilter = array_slice(func_get_args(),3);
if (
$aFilter && gettype($aFilter[0])=="array") $aFilter=$aFilter[0];
$adFilter = array();
// 现在将目录过滤器移动到单独的数组中:
foreach ($aFilter as $i=>$filter) // 对于每个目录过滤器...
if (($pos=stripos(" $filter","d")) && $pos<3) { // 下一行删除 'd'
$adFilter[] = substr($filter,0,$pos-1) . substr($filter,$pos);
unset(
$aFilter[$i]); }
$aFilter = array_merge($aFilter); // 重置索引

$aRes = array(); // 结果,$aAcc 是一个累加器
$aDir = array($path); // 要检查的目录
for ($i=$levels>0?$levels++:-1;($aAcc=array())||$i--&&$aDir;$aDir=$aAcc)
while (
$dir = array_shift($aDir))
foreach (
scandir ($dir) as $fileOrDir)
if (
$fileOrDir!="." && $fileOrDir!="..") {
if (
$dirP = is_dir ($rp="$dir$dS$fileOrDir"))
if (
pathFilter("$rp$dS", $adFilter))
$aAcc[] = $rp;
if (
$i<$levels-1 && ($types & (2-$dirP)))
if (
pathFilter($rp, $aFilter))
$aRes[] = ($dirP?"*":"") . $rp; }
return
$aRes;
}
?>

用法示例
<?php
define
("_", NULL);
// 这将查找 c:\Photo 下所有非 .jpg、非 .Thumbs.db 文件
$aFiles = dirList('c:\Photo', _, 0, '-/\.jpg$/i', '-/\\\\Thumbs.db$/');
$aFiles = dirList(); // 查找当前目录中的文件
// 下一行将查找非 Photo(s) 子目录中的 .jpg 文件,排除 Temporary Internet Files
set_time_limit(60); // 从顶层迭代可能需要一段时间
$aFiles = dirList("c:\\", _, 0, '/\.jpg$/i', '-d/\\\\Photos?$/i', '-d/Temporary Internet/i');
?>

请注意,如果扫描大型目录结构,此函数将消耗大量时间
(这就是 '[-]d/.../' 过滤器的作用)。

来自维也纳的Csaba Gabor
Pawel Dlugosz
19年前
对于包含诸如(例如)-.jpg 之类文件的目录,scandir 的结果有点“奇怪”;)

<?php

$dir
= '/somedir';
$files = scandir($dir);
print_r($files);
?>

数组
(
[0] => -.jpg
[1] => .
[2] => ..
[3] => foo.txt
[4] => somedir
)

注意 - 排序使用 ASCII 顺序 :)
Stan P. van de Burgt
20年前
scandir(),带有对文件名进行正则表达式匹配和基于 stat() 的排序选项。

<?php
function myscandir($dir, $exp, $how='name', $desc=0)
{
$r = array();
$dh = @opendir($dir);
if (
$dh) {
while ((
$fname = readdir($dh)) !== false) {
if (
preg_match($exp, $fname)) {
$stat = stat("$dir/$fname");
$r[$fname] = ($how == 'name')? $fname: $stat[$how];
}
}
closedir($dh);
if (
$desc) {
arsort($r);
}
else {
asort($r);
}
}
return(
array_keys($r));
}

$r = myscandir('./book/', '/^article[0-9]{4}\.txt$/i', 'ctime', 1);
print_r($r);
?>

文件可以按名称和 stat() 属性排序,升序和降序

name 文件名
dev 设备号
ino inode 号
mode inode 保护模式
nlink 链接数
uid 所有者的用户 ID
gid 所有者的组 ID
rdev 设备类型,如果 inode 设备*
size 以字节为单位的大小
atime 最后访问时间(Unix 时间戳)
mtime 最后修改时间(Unix 时间戳)
ctime 最后 inode 更改时间(Unix 时间戳)
blksize 文件系统 IO 的块大小*
blocks 分配的块数
simon dot riget at gmail dot com
8 年前
这是一个简单而通用的函数,它返回一个匹配通配符的文件数组树

<?php
// 在树中列出文件,匹配通配符 * 和 ?
function tree($path){
static
$match;

// 查找路径的真实目录部分,并设置匹配参数
$last=strrpos($path,"/");
if(!
is_dir($path)){
$match=substr($path,$last);
while(!
is_dir($path=substr($path,0,$last)) && $last!==false)
$last=strrpos($path,"/",-1);
}
if(empty(
$match)) $match="/*";
if(!
$path=realpath($path)) return;

// 列出文件
foreach(glob($path.$match) as $file){
$list[]=substr($file,strrpos($file,"/")+1);
}

// 处理子目录
foreach(glob("$path/*", GLOB_ONLYDIR) as $dir){
$list[substr($dir,strrpos($dir,"/",-1)+1)]=tree($dir);
}

return @
$list;
}
?>
fazle dot elahee at gmail dot com
12 年前
/**
* 此函数将递归扫描子文件夹和文件夹中的所有文件。
*
* @author Fazle Elahee
*
*/

function scanFileNameRecursivly($path = '', &$name = array() )
{
$path = $path == ''? dirname(__FILE__) : $path;
$lists = @scandir($path);

if(!empty($lists))
{
foreach($lists as $f)
{

if(is_dir($path.DIRECTORY_SEPARATOR.$f) && $f != ".." && $f != ".")
{
scanFileNameRecursivly($path.DIRECTORY_SEPARATOR.$f, &$name);
}
else
{
$name[] = $path.DIRECTORY_SEPARATOR.$f;
}
}
}
return $name;
}

$path = "/var/www/SimplejQueryDropdowns";
$file_names = scanFileNameRecursivly($path);

echo "<pre>";
var_dump($file_names);
echo "</pre>";
fatpratmatt dot at dot gmail dot com
16 年前
此函数生成选定目录和所有子目录中所有文件的列表,将它们放入非多维数组中并返回它们。

此页面上的大多数递归函数仅返回多维数组。

这实际上是对其他人函数的修改(感谢 mail at bartrail dot de ;])

<?php
function scanDirectories($rootDir, $allData=array()) {
// 如果需要,将文件名设置为不可见
$invisibleFileNames = array(".", "..", ".htaccess", ".htpasswd");
// 遍历根目录的内容
$dirContent = scandir($rootDir);
foreach(
$dirContent as $key => $content) {
// 过滤所有不可访问的文件
$path = $rootDir.'/'.$content;
if(!
in_array($content, $invisibleFileNames)) {
// 如果内容是文件且可读,则添加到数组中
if(is_file($path) && is_readable($path)) {
// 保存带有路径的文件名
$allData[] = $path;
// 如果内容是目录且可读,则添加路径和名称
}elseif(is_dir($path) && is_readable($path)) {
// 递归回调以打开新目录
$allData = scanDirectories($path, $allData);
}
}
}
return
$allData;
}
?>

示例输出

print_r(scanDirectories("www"));
---
数组
(
[0] => www/index.php
[1] => www/admin.php
[3] => www/css/css.css
[4] => www/articles/2007/article1.txt
[4] => www/articles/2006/article1.txt
[8] => www/img/img1.png
)
SPekary
7 年前
除非您指定不排序,否则文件名将按 ASCII 字母顺序排序,这意味着数字首先,然后是大写字母,然后是小写字母,即使在操作系统上,其文件系统在执行自己的排序时会忽略文件名的区分大小写。

例如,在 Mac OS 上,以下文件将在 Finder 中按此顺序显示,当您的磁盘使用标准文件系统格式化时
1file.php
a.inc
B.txt
c.txt

但是,scandir 将按以下顺序生成数组
1file.php
B.txt
a.inc
c.txt
carneiro at isharelife dot com dot br
12 年前
<?php
/**
* 获取表示目录树的数组
* @param string $directory 目录路径
* @param bool $recursive 包含子目录
* @param bool $listDirs 列表中包含目录
* @param bool $listFiles 列表中包含文件
* @param regex $exclude 排除与该正则表达式匹配的路径
*/
function directoryToArray($directory, $recursive = true, $listDirs = false, $listFiles = true, $exclude = '') {
$arrayItems = array();
$skipByExclude = false;
$handle = opendir($directory);
if (
$handle) {
while (
false !== ($file = readdir($handle))) {
preg_match("/(^(([\.]){1,2})$|(\.(svn|git|md))|(Thumbs\.db|\.DS_STORE))$/iu", $file, $skip);
if(
$exclude){
preg_match($exclude, $file, $skipByExclude);
}
if (!
$skip && !$skipByExclude) {
if (
is_dir($directory. DIRECTORY_SEPARATOR . $file)) {
if(
$recursive) {
$arrayItems = array_merge($arrayItems, directoryToArray($directory. DIRECTORY_SEPARATOR . $file, $recursive, $listDirs, $listFiles, $exclude));
}
if(
$listDirs){
$file = $directory . DIRECTORY_SEPARATOR . $file;
$arrayItems[] = $file;
}
} else {
if(
$listFiles){
$file = $directory . DIRECTORY_SEPARATOR . $file;
$arrayItems[] = $file;
}
}
}
}
closedir($handle);
}
return
$arrayItems;
}
?>
To Top