PHP中深层递归的目录结构数组

时间:2009-06-04 18:23:17

标签: php arrays recursion

我正在尝试将硬盘上的一些文件夹放入阵列中。

例如,度假照片。 假设我们有这样的结构:

  • 设置1
    • 第1组第1项
    • 第1组第2项
    • 第1集的项目
  • 设置2
    • 第2组的子集1
      • 第2组第1项的第1项
      • 第2组子集1的项目
    • 第2组的第2集
    • 随机文件,而不是目录。
  • 设置3
  • ...

我希望有这样的东西,作为一个数组 意思是我有一个大数组,在该数组中有更多数组。每个集合和子集都有自己的数组。

我试图让它看起来像这样:

Array
(
    [Set 1] => Array([0] => Item 1 of Set 1, [1] => Item 1 of Set 1,...)
    [Set 2] => Array([Subnet 1] => Array([0] => Item 1 of Subset 1 of Set 2,[1] => ...), [Subnet 2] => Array([0] => ..., ..., ...), ..., [0] => Random File)
    [set 3] => Array(...)
    ...
)

我遇到了这个:http://www.the-art-of-web.com/php/dirlist/

但这不是我想要的。我一直在干涉它,但它只给我带来麻烦。

这是一个示例,查看更大分辨率的源(没有明显点击...)。 Example

5 个答案:

答案 0 :(得分:40)

我建议使用DirectoryIterator来构建数组

这是我快速拼凑的片段,但我目前没有测试环境,所以请准备调试它。

$fileData = fillArrayWithFileNodes( new DirectoryIterator( '/path/to/root/' ) );

function fillArrayWithFileNodes( DirectoryIterator $dir )
{
  $data = array();
  foreach ( $dir as $node )
  {
    if ( $node->isDir() && !$node->isDot() )
    {
      $data[$node->getFilename()] = fillArrayWithFileNodes( new DirectoryIterator( $node->getPathname() ) );
    }
    else if ( $node->isFile() )
    {
      $data[] = $node->getFilename();
    }
  }
  return $data;
}

答案 1 :(得分:14)

没有任何错误处理的简单实现:

function dirToArray($dir) {
    $contents = array();
    # Foreach node in $dir
    foreach (scandir($dir) as $node) {
        # Skip link to current and parent folder
        if ($node == '.')  continue;
        if ($node == '..') continue;
        # Check if it's a node or a folder
        if (is_dir($dir . DIRECTORY_SEPARATOR . $node)) {
            # Add directory recursively, be sure to pass a valid path
            # to the function, not just the folder's name
            $contents[$node] = dirToArray($dir . DIRECTORY_SEPARATOR . $node);
        } else {
            # Add node, the keys will be updated automatically
            $contents[] = $node;
        }
    }
    # done
    return $contents;
}

答案 2 :(得分:6)

基于@soulmerge's answer的代码。我刚删除了一些nits和注释,并使用$startpath作为我的起始目录。 (谢谢@soulmerge!)

function dirToArray($dir) {
    $contents = array();
    foreach (scandir($dir) as $node) {
        if ($node == '.' || $node == '..') continue;
        if (is_dir($dir . '/' . $node)) {
            $contents[$node] = dirToArray($dir . '/' . $node);
        } else {
            $contents[] = $node;
        }
    }
    return $contents;
}

$r = dirToArray($startpath);
print_r($r);

答案 3 :(得分:2)

我在PEAR File_Find包中取得了成功,特别是the mapTreeMultiple() method。您的代码将变为:

require_once 'File/Find.php';
$fileList = File_Find::mapTreeMultiple($dirPath);

这应该返回一个类似于你要求的数组。

答案 4 :(得分:0)

所以6年后....

我需要一个类似@tim&@soulmerge的答案的解决方案。我试图为默认codeigniter文件夹中的所有php文件做批量php UnitTest模板。

这是我过程的第一步,以数组的形式获取目录/文件夹的完整递归内容。然后重新创建文件结构,目录中包含名称正确的文件,类结构,方括号,方法和注释部分,可随时为php UnitTest填充。

总结:给出一个目录名称,将其中所有目录的单层数组作为键,并将其中的所有文件作为值。

我进一步扩展了他们的答案,您将获得以下信息:

function getPathContents($path)
{
     // was a file path provided?
     if ($path === null){
        // default file paths in codeigniter 3.0
        $dirs = array(
            './models',
            './controllers'
        );
    } else{
        // file path was provided
        // it can be a comma separated list or singular filepath or file
        $dirs = explode(',', $path);
    }
    // final array
    $contents = array();
    // for each directory / file given
    foreach ($dirs as $dir) {
        // is it a directory?
        if (is_dir($dir)) {
            // scan the directory and for each file inside
            foreach (scandir($dir) as $node) {
                // skip current and parent directory
                if ($node === '.' || $node === '..') {
                    continue;
                } else {
                    // check for sub directories
                    if (is_dir($dir . '/' . $node)) {
                        // recursive check for sub directories
                        $recurseArray = getPathContents($dir . '/' . $node);
                        // merge current and recursive results
                        $contents = array_merge($contents, $recurseArray);
                    } else {
                        // it a file, put it in the array if it's extension is '.php'
                        if (substr($node, -4) === '.php') {
                            // don'r remove periods if current or parent directory was input
                            if ($dir === '.' || $dir === '..') {
                                $contents[$dir][] = $node;
                            } else {
                                // remove period from directory name 
                                $contents[str_replace('.', '', $dir)][] = $node;
                            }
                        }
                    }
                }
            }
        } else {
            // file name was given
            $contents[] = $dir; 
        }
    }
    return $contents;
}