轻松去除 Linux 环境中 scandir() 拾取的点
<?php
$directory = '/path/to/my/directory';
$scanned_directory = array_diff(scandir($directory), array('..', '.'));
?>
(PHP 5, PHP 7, PHP 8)
scandir — 列出指定路径中的文件和目录
$directory
, int $sorting_order
= SCANDIR_SORT_ASCENDING
, ?resource $context
= null
): array|false返回一个包含 directory
中的文件和目录的 array。
directory
要扫描的目录。
sorting_order
默认情况下,排序顺序是按字母顺序升序。如果可选的 sorting_order
设置为 SCANDIR_SORT_DESCENDING
,则排序顺序为按字母顺序降序。如果设置为 SCANDIR_SORT_NONE
,则结果不排序。
context
有关 context
参数的描述,请参阅手册的 流部分。
版本 | 说明 |
---|---|
8.0.0 |
context 现在可以为 null。 |
示例 #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] => . )
轻松去除 Linux 环境中 scandir() 拾取的点
<?php
$directory = '/path/to/my/directory';
$scanned_directory = array_diff(scandir($directory), array('..', '.'));
?>
这是我的两分钱。我想创建一个目录结构的递归数组。我希望使用 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
}
)
有人写道 array_slice 可用于快速删除目录条目 "." 和 ".."。但是,"-" 是一个有效的条目,它会出现在它们之前,因此 array_slice 会删除错误的条目。
我需要找到一种方法来获取目录和目录所有子目录中的所有文件的完整路径。
这是我的解决方案:递归函数!
<?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;
}
?>
需要一些可以返回单个或多个目录的内容,递归或非递归,
用于所有文件或指定的文件扩展名,这些文件扩展名将
可以从任何范围或脚本轻松访问。
我还想允许重载,因为有时我懒得传递所有参数。
<?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);
?>
获取没有点的文件列表的最快方法。
<?php
$files = array_slice(scandir('/path/to/directory/'), 2);
一个简单的递归函数,用于列出目录中的所有文件和子目录
<?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;
}
?>
我是如何解决 '.' 和 '..' 的问题的
$x = scandir__DIR__; // 任何目录
foreach ($x as $key => $value) {
if ('.' !== $value && '..' !== $value){
echo $value;
}
}
简单且有效
增强版 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 的 '/' 之前)'-' => NOT。
// 第一个字符(在可能的 '-' 之后)'d' => 应用于目录名称
// 过滤器可以作为字符串数组或字符串列表传递
// 注意输出目录以 '*' 为前缀(在返回行之前完成)
$dS = DIRECTORY_SEPARATOR;
if (!($path = realpath($path?$path:getcwd()))) return array(); // 路径错误
// 下一行去除驱动器上的终止 \(有效,因为 c: == c:\ 在 PHP 上)。在 *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
/**
* 此函数将递归扫描子文件夹和文件夹中的所有文件。
*
* @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>";
对于包含像 (例如) -.jpg 这样的文件的目录,scandir 的结果有点“奇怪”;)
<?php
$dir = '/somedir';
$files = scandir($dir);
print_r($files);
?>
数组
(
[0] => -.jpg
[1] => .
[2] => ..
[3] => foo.txt
[4] => somedir
)
注意 - 排序按 ASCII 顺序进行 :)
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 已分配的块数
此函数生成所选目录及其所有子目录中的所有文件的列表,将它们放入一个非多维数组中并返回它们。
此页面上的大多数递归函数只返回一个多维数组。
这实际上是对其他人的函数的修改(感谢 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
)
如果你使用 array_diff() 来消除 "." 和 "..",你必须在结果上使用 array_values(),因为 array_diff() 将返回一个关联数组,这可能会导致从 0 开始的 for 循环出现问题。
$files = array_values(array_diff(scandir($directory), array('..', '.')));
忍者如何检索文件列表、按扩展名过滤的文件或目录
<?php
//NNNIIIinnnjaaa::
//没有目录的文件数组... 可选地按扩展名过滤
function file_list($d,$x){
foreach(array_diff(scandir($d),array('.','..')) as $f)if(is_file($d.'/'.$f)&&(($x)?ereg($x.'$',$f):1))$l[]=$f;
return $l;
}
//NNNIIIinnnjaaa::
//目录数组
function dir_list($d){
foreach(array_diff(scandir($d),array('.','..')) as $f)if(is_dir($d.'/'.$f))$l[]=$f;
return $l;
}
/********************************************************************\
PRETTY PRETTY LIGHTS (DOCUMENTATION)
\********************************************************************/
/********************************************************************
重载的 PHP 文件列表函数:
array file_list ( string $directory [, string $file_extension] )
$directory
路径,不包含反斜杠,例如 "/home/public_html/blarg"
$file_extention
可选地过滤特定文件名扩展名,例如 ".jpg"
>>>>>>>>>>>>>>>>>>>>>>>>>>>> TRANSLATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<
file_list("/home"); //返回文件列表(没有目录)
file_list("/home", ".jpg"); //只返回 .jpg 文件列表
\********************************************************************/
//(注意:下面的一个斜杠 (/) 使你能启用所有的测试函数,猜猜在哪里 ;-))
/********************************************************************\
// TEST FUNCTIONS... IF THESE WORK, THIS FUNCTION WORKS ON THIS PLATFORM
echo "<hr><b>File List:</b><br>";
$n = file_list(getcwd());
if($n) foreach($n as $f) echo "$f<br>"; //当前文件
echo "<hr><b>Files with extension .php:</b><br>";
$n = file_list(getcwd(),".php");
if($n) foreach($n as $f) echo "$f<br>"; //具有 .php 扩展名的文件
echo "<hr><b>Directories:</b><br>";
$d = dir_list(getcwd());
if($d) foreach($d as $f) echo "$f<br>"; //目录
/********************************************************************/
/************\
RUNTIME NOTES:
file_list($arg1); // php 会发出警告说没有第二个参数,但我们知道,这没关系
\************/
/*******************************\
TESTED AND WORKING ON 2009.04.30:
OS: Linux 2.6.9-78.0.17.ELsmp
APACHE: 2.2.9
PHP: 5.2.5
\*******************************/
?>
除非你指定不排序,否则文件名将按 ASCII 字母顺序排序,这意味着数字排在首位,然后是大写字母,然后是小写字母,即使在操作系统上也是如此,这些操作系统在进行自身排序时会忽略文件系统中文件名的区分大小写。
例如,在 Mac OS 上,以下文件将在 Finder 中按此顺序显示,当你的磁盘使用标准文件系统格式化时
1file.php
a.inc
B.txt
c.txt
但是,scandir 会按以下顺序生成数组
1file.php
B.txt
a.inc
c.txt
<?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;
}
?>
这是一个简单而通用的函数,它返回一个包含文件的数组树,并匹配通配符
<?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;
}
?>
只是好奇想统计一下项目中的文件和行数
<?php
function DirLineCounter( $dir , $result = array('lines_html' => false, 'files_count' => false, 'lines_count' => false ), $complete_table = true )
{
$file_read = array( 'php', 'html', 'js', 'css' );
$dir_ignore = array();
$scan_result = scandir( $dir );
foreach ( $scan_result as $key => $value ) {
if ( !in_array( $value, array( '.', '..' ) ) ) {
if ( is_dir( $dir . DIRECTORY_SEPARATOR . $value ) ) {
if ( in_array( $value, $dir_ignore ) ) {
continue;
}
$result = DirLineCounter( $dir . DIRECTORY_SEPARATOR . $value, $result, false );
}
else {
$type = explode( '.', $value );
$type = array_reverse( $type );
if( !in_array( $type[0], $file_read ) ) {
continue;
}
$lines = 0;
$handle = fopen( $dir . DIRECTORY_SEPARATOR . $value, 'r' );
while ( !feof( $handle ) ) {
if ( is_bool( $handle ) ) {
break;
}
$line = fgets( $handle );
$lines++;
}
fclose( $handle );
$result['lines_html'][] = '<tr><td>' . $dir . '</td><td>' . $value . '</td><td>' . $lines . '</td></tr>';
$result['lines_count'] = $result['lines_count'] + $lines;
$result['files_count'] = $result['files_count'] + 1;
}
}
}
if ( $complete_table ) {
$lines_html = implode('', $result['lines_html']) . '<tr><td></td><td style="border: 1px solid #222">Files Total: ' . $result['files_count'] . '</td><td style="border: 1px solid #222">Lines Total: ' . $result['lines_count'] . '</td></tr>';
return '<table><tr><td style="width: 60%; background-color:#ddd;">Dir</td><td style="width: 30%; background-color:#ddd;">File</td><td style="width: 10%; background-color:#ddd;">Lines</td></tr>' . $lines_html . '</table>';
}
else {
return $result;
}
}
echo DirLineCounter( '.' );
?>
这是一个用于统计目录下文件数量的函数
<?php
function countFiles($dir){
$files = array();
$directory = opendir($dir);
while($item = readdir($directory)){
// 我们过滤掉不想显示的元素 ".", ".." 和 ".svn"
if(($item != ".") && ($item != "..") && ($item != ".svn") ){
$files[] = $item;
}
}
$numFiles = count($files);
return $numFiles;
}
?>
<?php
//-- 使用 SCANDIR 进行目录导航
//--
//-- 可选放置
$exclude_list = array(".", "..", "example.txt");
if (isset($_GET["dir"])) {
$dir_path = $_SERVER["DOCUMENT_ROOT"]."/".$_GET["dir"];
}
else {
$dir_path = $_SERVER["DOCUMENT_ROOT"]."/";
}
//-- 到这里
function dir_nav() {
global $exclude_list, $dir_path;
$directories = array_diff(scandir($dir_path), $exclude_list);
echo "<ul style='list-style:none;padding:0'>";
foreach($directories as $entry) {
if(is_dir($dir_path.$entry)) {
echo "<li style='margin-left:1em;'>[`] <a href='?dir=".$_GET["dir"].$entry."/"."'>".$entry."</a></li>";
}
}
echo "</ul>";
//-- 分隔符
echo "<ul style='list-style:none;padding:0'>";
foreach($directories as $entry) {
if(is_file($dir_path.$entry)) {
echo "<li style='margin-left:1em;'>[ ] <a href='?file=".$_GET["dir"].$entry."'>".$entry."</a></li>";
}
}
echo "</ul>";
}
dir_nav();
//-- 可选放置
if (isset($_GET["file"])) {
echo "<div style='margin:1em;border:1px solid Silver;'>";
highlight_file($dir_path.$_GET['file']);
echo "</div>";
}
//-- 到这里
//--
//-- 因为我爱 php.net
?>
这是我的递归函数,将目录放入新的数组键中,其内容也在其中。
/* find_files( string, &array )
** 递归函数,返回包含在给定目录中的文件夹和文件的二维数组**
** function find_files($dir, &$dir_array)**
*/
function find_files($dir, &$dir_array)
{
// 创建当前目录的数组
$files = scandir($dir);
if(is_array($files))
{
foreach($files as $val)
{
// 跳过主页和上一个列表
if($val == '.' || $val == '..')
continue;
// 如果是目录,则深入,否则将文件添加到目录键
if(is_dir($dir.'/'.$val))
{
// 将值添加到当前数组,目录或文件
$dir_array[$dir][] = $val;
find_files($dir.'/'.$val, $dir_array);
}
else
{
$dir_array[$dir][] = $val;
}
}
}
ksort($dir_array);
}
// 示例
$folder_list = array();
find_files('/path', $folder_list)
var_dump($folder_list);
array(3) {
["directory_01"]=>
array(4) {
[0]=>
string(12) "directory_02"
[1]=>
string(12) "directory_03"
[2]=>
string(11) "file_01.txt"
[3]=>
string(11) "file_02.txt"
}
["directory_01/directory_02"]=>
array(2) {
[0]=>
string(11) "file_03.txt"
[1]=>
string(11) "file_04.txt"
}
["directory_01/directory_03"]=>
array(2) {
[0]=>
string(11) "file_05.txt"
[1]=>
string(11) "file_06.txt"
}
}
大家好,
我刚刚为 getDirectoryTree 函数添加了一个扩展过滤器,以便它可以过滤文件夹/子文件夹中文件的扩展名。
<?php
function getDirectoryTree( $outerDir , $x){
$dirs = array_diff( scandir( $outerDir ), Array( ".", ".." ) );
$dir_array = Array();
foreach( $dirs as $d ){
if( is_dir($outerDir."/".$d) ){
$dir_array[ $d ] = getDirectoryTree( $outerDir."/".$d , $x);
}else{
if (($x)?ereg($x.'$',$d):1)
$dir_array[ $d ] = $d;
}
}
return $dir_array;
}
$dirlist = getDirectoryTree('filmes','flv');
?>
我一直在寻找一种简单的方法来获取特定目录中的所有文件。我找到了以下代码行,它将生成一个只包含文件的数组列表。当然,也可以对目录执行相同的操作。
<?php
$files = array_filter(scandir($directory), function($file) { return is_file($file); })
?>
列出目录中所有项目的简单方法
<?php
$itemnum = 1;
$dir = 'C:/Path/To/Directory';
foreach(scandir($dir) as $item){
if (!($item == '.')) {
if (!($item == '..')) {
echo($itemnum." = ".$item."<br>");
$itemnum = ($itemnum + 1);
}}}
?>
我创建了这个函数来用一个数组表示目录树,该数组使用文件或目录名作为键,并使用完整路径作为文件的键值。目录是嵌套的数组。
<?php
function generatePathTree($rootPath) {
$pathStack = array($rootPath);
$contentsRoot = array();
$contents = &$contentsRoot;
while ($path = array_pop($pathStack)) {
$contents[basename($path)] = array();
$contents = &$contents[basename($path)];
foreach (scandir($path) as $filename) {
if ('.' != substr($filename, 0, 1)) {
$newPath = $path.'/'.$filename;
if (is_dir($newPath)) {
array_push($pathStack, $newPath);
$contents[basename($newPath)] = array();
} else {
$contents[basename($filename)] = $newPath;
}
}
}
}
return $contentsRoot[basename($rootPath)];
}
?>
该函数将返回类似于以下内容的结果
数组
(
[index.php] => /usr/local/www/index.php
[js] => Array
(
[async.js] => /usr/local/www/js/async.js
[dom.js] => /usr/local/www/js/dom.js
[effects.js] => /usr/local/www/js/effects.js
[prototype.js] => /usr/local/www/js/prototype.js
)
[logo.png] => /usr/local/www/logo.png
[server.php] => /usr/local/www/server.php
[test.js] => /usr/local/www/test.js
)
回到 scandir 的主题,我为一个需要将目录与文件分离的函数编写了这个函数。由于我仍然在从我上一个例子中学习,所以我决定添加它以便可以对其进行批评。
<?php
function dirlist($dir, $bool = "dirs"){
$truedir = $dir;
$dir = scandir($dir);
if($bool == "files"){ // 根据第二个参数动态定义函数
$direct = 'is_dir';
}elseif($bool == "dirs"){
$direct = 'is_file';
}
foreach($dir as $k => $v){
if(($direct($truedir.$dir[$k])) || $dir[$k] == '.' || $dir[$k] == '..' ){
unset($dir[$k]);
}
}
$dir = array_values($dir);
return $dir;
}
?>
<?php
print_r(dirlist("../")); // 确认子目录的数组
print_r(dirlist("../", "files") // 确认目录中的文件列表
?>
如果您的文件夹包含许多文件和/或子文件夹,递归执行 scandir 很可能会导致您的应用程序变慢,或者由于生成的数组大小很大而导致内存消耗急剧增加。
为了解决这个问题,以及为了更轻松地处理文件夹中的文件,我编写了一个函数,该函数递归地读取文件夹及其子文件夹,并在每次匹配时调用一个函数。
<?php
/**
* 遍历文件夹中的每个文件并调用函数。
*
* @author Vasil Rangelov a.k.a. boen_robot
*
* @param string $callback 要调用的函数。它必须接受一个参数,该参数是文件的相对路径。
* @param string $dir 要遍历的目录。
* @param array $types 要为其调用函数的文件类型。留空表示匹配所有类型。
* @param bool $recursive 是否也列出子文件夹。
* @param string $baseDir 要附加到回调将接收的每个文件路径开头的字符串。
*/
function dir_walk($callback, $dir, $types = null, $recursive = false, $baseDir = '') {
if ($dh = opendir($dir)) {
while (($file = readdir($dh)) !== false) {
if ($file === '.' || $file === '..') {
continue;
}
if (is_file($dir . $file)) {
if (is_array($types)) {
if (!in_array(strtolower(pathinfo($dir . $file, PATHINFO_EXTENSION)), $types, true)) {
continue;
}
}
$callback($baseDir . $file);
}elseif($recursive && is_dir($dir . $file)) {
dir_walk($callback, $dir . $file . DIRECTORY_SEPARATOR, $types, $recursive, $baseDir . $file . DIRECTORY_SEPARATOR);
}
}
closedir($dh);
}
}
?>
当然,由于它是递归的,一个包含许多层文件夹的文件夹可能会消耗大量内存,但另一方面,这里所有其他递归 scandir 实现也是如此。
顺便说一下,还有 RecursiveDirectoryIterator SPL 类
http://bg.php.net/manual/en/class.recursivedirectoryiterator.php
即使使用相同的方法,它也可能更快并保持更深层次(因为它在 C 级工作),但这个将始终工作,无论设置如何……即使在 PHP4 上。
关键是,避免使用递归 scandir 实现。
我写了这个函数来读取一个文件夹并将它包含的所有文件夹和子文件夹放入一个数组中。
<?php
// 初始化空数组,否则会发生错误
$folders = array();
function recursive_subfolders($folders) {
// 在这里设置路径
$path = '/path/to/folder';
// 创建初始 "Folders" 数组
if ($dir = opendir($path)) {
$j = 0;
while (($file = readdir($dir)) !== false) {
if ($file != '.' && $file != '..' && is_dir($path.$file)) {
$j++;
$folders[$j] = $path . $file;
}
}
}
closedir($dir);
// 然后检查该数组中的每个文件夹是否有子文件夹,并将子文件夹添加到 "Folders" 数组中。
$j = count($folders);
foreach ($folders as $folder) {
if ($dir = opendir($folder)) {
while (($file = readdir($dir)) !== false) {
$pathto = $folder. '/' . $file;
if ($file != '.' && $file != '..' && is_dir($pathto) && !in_array($pathto, $folders)) {
$j++;
$folders[$j] = $pathto;
$folders = recursive_subfolders($folders);
}
}
}
closedir($dir);
}
sort($folders);
return $folders;
}
$folders = recursive_subfolders($folders);
?>
$folders 现在包含一个数组,其中包含每个子文件夹的完整路径。例如
数组
(
[0] => /path/to/folder/dir1
[1] => /path/to/folder/dir1/subdir
[2] => /path/to/folder/dir1/subdir/subsubdir
[3] => /path/to/dolfer/dir2
)
此函数仅在 Linux 上测试过。
// 极简版递归扫描
function rscandir($dir){
$dirs = array_fill_keys( array_diff( scandir( $dir ), array( '.', '..' ) ), array());
foreach( $dirs as $d => $v )
if( is_dir($dir."/".$d) )
$dirs[$d] = rscandir($dir."/".$d);
return $dirs;
}
一直在寻找一种使用掩码搜索文件/目录的简单方法。这是一个这样的函数。
默认情况下,此函数将在内存中保留 scandir() 的结果,以避免多次扫描同一个目录。
需要至少 PHP5。
<?php
function sdir( $path='.', $mask='*', $nocache=0 ){
static $dir = array(); // 在内存中缓存结果
if ( !isset($dir[$path]) || $nocache) {
$dir[$path] = scandir($path);
}
foreach ($dir[$path] as $i=>$entry) {
if ($entry!='.' && $entry!='..' && fnmatch($mask, $entry) ) {
$sdir[] = $entry;
}
}
return ($sdir);
}
?>
由于 scandir() 返回一个数组,这里有一个更简洁的方法来处理列出目录时 '.' 和 '..' 的问题
<?php
$target = '/';
$weeds = array('.', '..');
$directories = array_diff(scandir($target), $weeds);
foreach($directories as $value)
{
if(is_dir($target.$value))
{
echo $value.'<br />';
}
}
?>
$path_abs = __DIR__ .'/test/';
if( DIRECTORY_SEPARATOR != substr($path, -1) || (DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR) == substr($path, -2))
{
throw new Error("指定了非标准路径。`{$path}`");
}
$scandir_result = scandir( $path, SCANDIR_SORT_DESCENDING );
for( $n = 0, $e = count($scandir_result) - 2; $n < $e; $n++ )
{
echo ($path . $scandir_result[$n]) .'<br/>';
}
<?php
/**
* 移除所有点号(.),包括可能存在的 `.DS_Store` 文件,并对结果数组进行重新索引。
*
* @param string $path_to_directory 目标目录的相对路径。
*
* @return array 重新索引后的文件数组。
*/
function get_the_files( $path_to_directory ) {
return array_slice( array_diff( scandir( $path_to_directory ), array( '..', '.', '.DS_Store' ) ), 0 );
}
?>
这是对 scanDirectories 函数的修改,它生成一个包含所选目录及其所有子目录中所有指定扩展名的文件的列表,扩展名存储在 $allowext 变量中。
<?php
function scanDirectories($rootDir, $allowext, $allData=array()) {
$dirContent = scandir($rootDir);
foreach($dirContent as $key => $content) {
$path = $rootDir.'/'.$content;
$ext = substr($content, strrpos($content, '.') + 1);
if(in_array($ext, $allowext)) {
if(is_file($path) && is_readable($path)) {
$allData[] = $path;
}elseif(is_dir($path) && is_readable($path)) {
// 递归回调以打开新目录
$allData = scanDirectories($path, $allData);
}
}
}
return $allData;
}
$rootDir = "www";
$allowext = array("zip","rar","html");
$files_array = scanDirectories($rootDir,$allowext);
print_r($files_array);
?>
function ScaniDir($path){
$ptd= opendir($path);
while (( $ptdf=readdir($ptd))){
$srca = $path.'/'.$ptdf;
if (is_file($srca) and pathinfo($srca, PATHINFO_EXTENSION)=='pdf') {$files['src'][]=$srca;$files['name'][]=explode('.',$ptdf)[0];}
}
return $files ;
}
一个不错的过滤 scandir 函数返回的文件/目录的方法。
<?php
function pathFilter ($path, $aFilter) {
// 如果 $path 通过 $aFilter 中的测试,则返回 true
// $aFilter 是一个正则表达式数组:[-]/regExp/modifiers
// 如果开头是 '-',则表示匹配时排除 $path(NOT 测试)
// 如果第一个表达式开头是 '-',则 $path 处于包含状态,除非它被排除。
// 否则,$path 处于排除状态,除非它通过过滤器测试被包含。
// 测试按顺序应用。
// NOT 测试仅在 $path 当前(在测试中)处于包含状态时才应用
// 其他测试仅在 $path 当前处于排除状态时才应用。 因此,
// array("/a/", "-/b/", "/c/") => 如果 $path 包含 c 或如果 $path 包含 a 但不包含 b,则通过
// array("/a/", "/c/", "-/b/") => 如果 $path 包含 a 或 c,但不包含 b,则通过
// array("-/b/", "/a/", "/c/") => 如果 $path 不包含 b,或者如果 $path 包含 a 或 c,则通过
if (!$aFilter) return true; // 如果没有过滤器,则自动包含(通过)
foreach ($aFilter as $filter) break; // 我们不知道它是如何索引的
$in = $filter[0]=="-"; // 根据第一个过滤器设置初始包含/排除状态
foreach ($aFilter as $filter) // 遍历过滤器
if ($in==$not=($filter[0]=="-")) // 仅在必要时进行测试
$in ^= preg_match(substr($filter,$not),$path); // 匹配时翻转包含/排除状态
return $in;
}
?>
来自维也纳的 Csaba Gabor
使用 scandir() 的变体,它返回按文件修改时间排序的内容。
<?php
function scandir_by_mtime($folder) {
$dircontent = scandir($folder);
$arr = array();
foreach($dircontent as $filename) {
if ($filename != '.' && $filename != '..') {
if (filemtime($folder.$filename) === false) return false;
$dat = date("YmdHis", filemtime($folder.$filename));
$arr[$dat] = $filename;
}
}
if (!ksort($arr)) return false;
return $arr;
}
?>
如果发生错误,则返回 false
否则它将返回一个类似于下面的数组。
数组
(
[20040813231320] => DSC00023.JPG
[20040813231456] => DSC00024.JPG
[20040814003728] => MOV00055.MPG
[20040814003804] => DSC00056.JPG
[20040814003946] => DSC00057.JPG
[20040814004030] => DSC00058.JPG
[20040814014516] => DSC00083.JPG
[20050401161718] => album.txt
)