PHP获取文件夹/子文件夹中每个文件到数组的路径?

Pap*_*eau 7 php arrays directory path multidimensional-array

可能重复:
PHP SPL RecursiveDirectoryIterator RecursiveIteratorIterator检索完整树

我不知道从哪里开始.但我必须获取文件夹中所有文件的路径以及路径中子文件夹的所有内容.例如,如果我有一个文件夹有五个文件夹,每个文件夹中有10个mp3等等...这意味着我的数组必须找到50个这些文件的路径.

后来我说我又添加了一个文件夹,里面有3个文件夹,每个文件夹有10个图像.

我的代码现在需要找到80个路径并将它们存储在一个数组中.

我的问题有意义吗?

更新:

我想要的输出是将所有这些路径存储在一个数组中.

但我会"爱"代码是动态的,这意味着如果我以后再添加10个文件夹,每个文件夹有17个子文件夹,每个文件夹都有大量不同的内容.我希望数组保存所有文件的文件路径.我知道这是有道理的.

hak*_*kre 25

您正在寻找的也称为递归目录遍历.这意味着,您将浏览所有目录并列出其中的子目录和文件.如果有一个子目录,它也会被遍历,依此类推 - 所以它是递归的.

您可以想象,当您编写软件时,这是您需要的一些常见内容,PHP支持您.它提供了一个RecursiveDirectoryIterator目录可以递归迭代和标准RecursiveIteratorIterator来进行遍历.然后,您可以通过简单的迭代轻松访问所有文件和目录,例如foreach:

$rootpath = '.';
$fileinfos = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($rootpath)
);
foreach($fileinfos as $pathname => $fileinfo) {
    if (!$fileinfo->isFile()) continue;
    var_dump($pathname);
}
Run Code Online (Sandbox Code Playgroud)

此示例首先指定要遍历的目录.我一直在拿现在的那个:

$rootpath = '.';
Run Code Online (Sandbox Code Playgroud)

下一行代码有点长,它确实实例化了目录迭代器,然后是迭代器 - 迭代器,以便可以在单个/平坦循环中遍历树状结构:

$fileinfos = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($rootpath)
);
Run Code Online (Sandbox Code Playgroud)

$fileinfos然后用简单的方法迭代它们foreach:

foreach($fileinfos as $pathname => $fileinfo) {
Run Code Online (Sandbox Code Playgroud)

在其中,有一个测试可以跳过所有目录输出.这是通过使用SplFileInfo迭代的对象完成的.它由递归目录迭代器提供,在处理文件时包含许多有用的属性和方法.您也可以返回文件扩展名,有关大小和时间的基本名称信息等等.

if (!$fileinfo->isFile()) continue;
Run Code Online (Sandbox Code Playgroud)

最后,我只输出路径名,该路径名是文件的完整路径:

var_dump($pathname);
Run Code Online (Sandbox Code Playgroud)

示例输出看起来像这样(这里是在Windows操作系统上):

string(12) ".\.buildpath"
string(11) ".\.htaccess"
string(33) ".\dom\xml-attacks\attacks-xml.php"
string(38) ".\dom\xml-attacks\billion-laughs-2.xml"
string(36) ".\dom\xml-attacks\billion-laughs.xml"
string(40) ".\dom\xml-attacks\quadratic-blowup-2.xml"
string(40) ".\dom\xml-attacks\quadratic-blowup-3.xml"
string(38) ".\dom\xml-attacks\quadratic-blowup.xml"
string(22) ".\dom\xmltree-dump.php"
string(25) ".\dom\xpath-list-tags.php"
string(22) ".\dom\xpath-search.php"
string(27) ".\dom\xpath-text-search.php"
string(29) ".\encrypt-decrypt\decrypt.php"
string(29) ".\encrypt-decrypt\encrypt.php"
string(26) ".\encrypt-decrypt\test.php"
string(13) ".\favicon.ico"
Run Code Online (Sandbox Code Playgroud)

如果存在无法访问的子目录,则以下内容将引发异常.实例化时,可以使用一些标志控制此行为RecursiveIteratorIterator:

$fileinfos = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator('.'),
    RecursiveIteratorIterator::LEAVES_ONLY,
    RecursiveIteratorIterator::CATCH_GET_CHILD
);
Run Code Online (Sandbox Code Playgroud)

我希望这是有益的.您还可以将其包装到您自己的类中,您还可以提供一个FilterIterator决定是否应该列出文件的决定foreach.


这种RecursiveDirectoryIteratorRecursiveIteratorIterator组合的力量源于其灵活性.上面没有涉及的是所谓的FilterIterators.我想我添加了另一个例子,它使用了两个自编的,相互放置以组合它们.

  • 一种是过滤掉以点开头的所有文件和目录(这些文件和目录在UNIX系统上被认为是隐藏文件,因此您不应该将这些信息提供给外部)
  • 另一个是将列表过滤到文件.这是以前 foreach 内部的检查.

此用法示例中的另一个更改是使用从迭代的根路径开始返回子路径的getSubPathname()函数,以便查找要查找的子路径.

此外,我明确添加了防止遍历的SKIP_DOTS标志...(技术上不是真的必要,因为过滤器会过滤那些以及它们是目录,但我认为它更正确)并返回路径,UNIX_PATHS因此路径的字符串始终是unix-像路径一样,无论底层操作系统如何,如果通过HTTP稍后通过HTTP请求这些值通常是个好主意:

$rootpath = '.';

$fileinfos = new RecursiveIteratorIterator(
    new FilesOnlyFilter(
        new VisibleOnlyFilter(
            new RecursiveDirectoryIterator(
                $rootpath,
                FilesystemIterator::SKIP_DOTS
                    | FilesystemIterator::UNIX_PATHS
            )
        )
    ),
    RecursiveIteratorIterator::LEAVES_ONLY,
    RecursiveIteratorIterator::CATCH_GET_CHILD
);

foreach ($fileinfos as $pathname => $fileinfo) {
    echo $fileinfos->getSubPathname(), "\n";
}
Run Code Online (Sandbox Code Playgroud)

此示例与前一个示例类似,尽管$fileinfos构建的配置略有不同.特别是有关过滤器的部分是新的:

    new FilesOnlyFilter(
        new VisibleOnlyFilter(
            new RecursiveDirectoryIterator($rootpath, ...)
        )
    ),
Run Code Online (Sandbox Code Playgroud)

因此目录迭代器被放入过滤器,过滤器本身被放入另一个过滤器.其余的没有改变.

这些过滤器的代码是相当直接的,他们与工作accept要么是功能true或者false是采取或过滤掉:

class VisibleOnlyFilter extends RecursiveFilterIterator
{
    public function accept()
    {
        $fileName = $this->getInnerIterator()->current()->getFileName();
        $firstChar = $fileName[0];
        return $firstChar !== '.';
    }
}

class FilesOnlyFilter extends RecursiveFilterIterator
{
    public function accept()
    {
        $iterator = $this->getInnerIterator();

        // allow traversal
        if ($iterator->hasChildren()) {
            return true;
        }

        // filter entries, only allow true files
        return $iterator->current()->isFile();
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是它.当然,您也可以将这些过滤器用于其他情况.例如,如果您有另一种目录列表.

另一个示例性输出与$rootpath切除:

test.html
test.rss
tests/test-pad-2.php
tests/test-pad-3.php
tests/test-pad-4.php
tests/test-pad-5.php
tests/test-pad-6.php
tests/test-pad.php
TLD/PSL/C/dkim-regdom.c
TLD/PSL/C/dkim-regdom.h
TLD/PSL/C/Makefile
TLD/PSL/C/punycode.pl
TLD/PSL/C/test-dkim-regdom.c
TLD/PSL/C/test-dkim-regdom.sh
TLD/PSL/C/tld-canon.h
TLD/PSL/generateEffectiveTLDs.php
Run Code Online (Sandbox Code Playgroud)

没有更多.git.svn目录遍历或文件列表,如.builtpath.project.


注意FilesOnlyFilterLEAVES_ONLY: 过滤器明确拒绝使用基于对象的目录链接SplFileInfo(仅存在的常规文件).所以这是一个基于文件系统的真正过滤.由于默认标志(此处也在示例中使用)
,RecursiveIteratorIterator因此仅提供非目录条目的另一种方法.此标志不能用作过滤器,并且与底层迭代器无关.它只是指定迭代不应该返回分支(这里:目录迭代器的目录).LEAVES_ONLY

  • 名字,你的意思是只有文件名?好吧,正如所写的`SplFileInfo`,该函数被称为[`getFilename()`](http://php.net/splfileinfo.getfilename.php),在您的情况下,只有文件名为`$ fileinfo-> getFilename ()`.仅限扩展使用[`$ fileinfo-> getExtension()`](http://www.php.net/splfileinfo.getextension.php)等等.您可以使用的每个函数与`SplFileInfo`对象一起使用.这就是为什么它优于`readdir`,因为你得到这些对象而不是愚蠢的字符串. (2认同)

msE*_*ays 5

如果您使用的是 Linux 并且不介意执行 shell 命令,则可以在一行中完成所有操作

$path = '/etc/php5/*'; // file filter, you could specify a extension using *.ext
$files = explode("\n", trim(`find -L $path`)); // -L follows symlinks

print_r($files);
Run Code Online (Sandbox Code Playgroud)

输出:

Array (
       [0] => /etc/php5/apache2
       [1] => /etc/php5/apache2/php.ini
       [2] => /etc/php5/apache2/conf.d
       [3] => /etc/php5/apache2/conf.d/gd.ini
       [4] => /etc/php5/apache2/conf.d/curl.ini
       [5] => /etc/php5/apache2/conf.d/mcrypt.ini
       etc...
      )
Run Code Online (Sandbox Code Playgroud)

仅使用 PHP 的下一个最短选择是 glob- 但它不会像您想要的那样扫描子目录。(你必须循环遍历结果,使用 is_dir() 然后再次调用你的函数

https://www.php.net/glob

$files = dir_scan('/etc/php5/*'); 
print_r($files);

function dir_scan($folder) {
    $files = glob($folder);
    foreach ($files as $f) {
        if (is_dir($f)) {
            $files = array_merge($files, dir_scan($f .'/*')); // scan subfolder
        }
    }
    return $files;
}
Run Code Online (Sandbox Code Playgroud)

所有其他方式都需要更多的代码,而不是做如此简单的事情


归档时间:

查看次数:

21292 次

最近记录:

12 年,4 月 前