在 Linux 环境中轻松去除 scandir() 获取到的点
<?php
$directory = '/path/to/my/directory';
$scanned_directory = array_diff(scandir($directory), array('..', '.'));
?>
(PHP 5, PHP 7, PHP 8)
scandir — 列出指定路径内的文件和目录
返回来自 directory
的文件和目录的 数组。
directory
将要扫描的目录。
sorting_order
默认情况下,排序顺序为升序字母顺序。如果可选的 sorting_order
设置为 SCANDIR_SORT_DESCENDING
,则排序顺序为降序字母顺序。如果将其设置为 SCANDIR_SORT_NONE
,则结果为未排序。
context
有关 context
参数的说明,请参阅手册的 流部分。
版本 | 描述 |
---|---|
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] => . )
在 Linux 环境中轻松去除 scandir() 获取到的点
<?php
$directory = '/path/to/my/directory';
$scanned_directory = array_diff(scandir($directory), array('..', '.'));
?>
这是我的 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
}
)
有人写道,可以使用 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);
我如何解决“.” 和 “..” 的问题
$x = scandir(__DIR__); // 任何目录
foreach ($x as $key => $value) {
if ('.' !== $value && '..' !== $value){
echo $value;
}
}
简单易用
一个简单的递归函数,用于列出目录中的所有文件和子目录
<?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;
}
?>
增强版的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
对于包含诸如(例如)-.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 分配的块数
这是一个简单而通用的函数,它返回一个匹配通配符的文件数组树
<?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;
}
?>
/**
* 此函数将递归扫描子文件夹和文件夹中的所有文件。
*
* @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>";
此函数生成选定目录和所有子目录中所有文件的列表,将它们放入非多维数组中并返回它们。
此页面上的大多数递归函数仅返回多维数组。
这实际上是对其他人函数的修改(感谢 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
)
除非您指定不排序,否则文件名将按 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;
}
?>