多维数组目录映射

时间:2017-07-28 21:30:57

标签: php multidimensional-array directory directory-structure

我正在尝试在多维数组中获取目录结构。

我到目前为止:

function dirtree($dir, $regex = '', $ignoreEmpty = false)
{
    if (!$dir instanceof DirectoryIterator) {
        $dir = new DirectoryIterator((string) $dir);
    }
    $dirs = array();
    $files = array();
    foreach ($dir as $node) {
        if ($node->isDir() && !$node->isDot()) {
            $tree = dirtree($node->getPathname(), $regex, $ignoreEmpty);
            if (!$ignoreEmpty || count($tree)) {
                $dirs[$node->getFilename()] = $tree;
            }
        } elseif ($node->isFile()) {
            $name = $node->getFilename();
            if ('' == $regex || preg_match($regex, $name)) {
                $files[] = $name;
            }
        }
    }
    asort($dirs);
    sort($files);
    return array_merge($dirs, $files);
}

但我在获取文件夹名称而不是索引0,1 .etc时遇到问题。 这似乎是因为我的目录有数字名称?

Array
(
    [0] => Array  // 0 should be the folder name
        (
            [0] => m_109225488_1.jpg
            [1] => t_109225488_1.jpg
        )

    [1] => Array
        (
            [0] => m_252543961_1.jpg
            [1] => t_252543961_1.jpg
        )

3 个答案:

答案 0 :(得分:2)

由于:Merge array without loss key index

,解决方案非常简单

而不是array_merge只需$dirs + $files

潜在的解决方案(Roger Gee指出的潜在问题):

function dirtree($dir, $regex = '', $ignoreEmpty = false)
{
    if (!$dir instanceof DirectoryIterator) {
        $dir = new DirectoryIterator((string) $dir);
    }
    $dirs = array();
    $files = array();
    foreach ($dir as $node) {
        if ($node->isDir() && !$node->isDot()) {
            $tree = dirtree($node->getPathname(), $regex, $ignoreEmpty);
            if (!$ignoreEmpty || count($tree)) {
                $dirs[$node->getFilename()] = $tree;
            }
        } elseif ($node->isFile()) {
            $name = $node->getFilename();
            if ('' == $regex || preg_match($regex, $name)) {
                $files[] = $name;
            }
        }
    }
    return $dirs + $files;
}

更好的解决方案?

function dirtree($dir, $regex = '', $ignoreEmpty = false)
{
    if (!$dir instanceof DirectoryIterator) {
        $dir = new DirectoryIterator((string) $dir);
    }
    $filedata = array();
    foreach ($dir as $node) {
        if ($node->isDir() && !$node->isDot()) {
            $tree = dirtree($node->getPathname(), $regex, $ignoreEmpty);
            if (!$ignoreEmpty || count($tree)) {
                $filedata[$node->getFilename()] = $tree;
            }
        } elseif ($node->isFile()) {
            $name = $node->getFilename();
            if ('' == $regex || preg_match($regex, $name)) {
                $filedata[] = $name;
            }
        }
    }
    return $filedata;
}

答案 1 :(得分:1)

使用数组联合操作很危险,因为您可能会覆盖现有文件。请考虑以下目录结构:

a       <-- directory
├── 0   <-- directory (empty)
├── b   <-- regular file
└── c   <-- directory
    └── d   <-- regular file

现在考虑使用数组union运行该操作。我得到以下结果:

array(2) {
  [0]=>
  array(0) {
  }
  ["c"]=>
  array(1) {
    [0]=>
    string(1) "d"
  }
}

注意常规文件b不存在?这是因为数组union操作优先于右操作数(包含常规文件)的0索引上的现有0索引。

我会坚持使用问题中的原始实现,对于不包含有效文件系统名称的文件(例如:files:)使用特殊存储桶。请注意,根据您的选择,这可能是特定于平台的。

对于原始实现,您可以通过调用值is_arrayis_scalar来确定索引是目录与常规文件。请注意,由于目录数组是array_merge的第一个参数,因此可以保证没有目录索引增加,并且始终引用正确的目录名。

以下是如何确定目录名称的方法:

function getDirectoryNames($result) {
    $ds = [];
    foreach ($result as $key => $value) {
        if (is_array($value)) {
            $ds[] = $key;
        }
    }
    return $ds;
}

答案 2 :(得分:0)

你要找的是ksort而不是asort。

<html>
<body>
<?php
function dirtree($dir, $regex = '', $ignoreEmpty = false)
{
    if (!$dir instanceof DirectoryIterator) {
        $dir = new DirectoryIterator((string) $dir);
    }
    $dirs = array();
    $files = array();
    foreach ($dir as $node) {
        if ($node->isDir() && !$node->isDot()) {
            $tree = dirtree($node->getPathname(), $regex, $ignoreEmpty);
            if (!$ignoreEmpty || count($tree)) {
                $dirs[$node->getFilename()] = $tree;
            }
        } elseif ($node->isFile()) {
            $name = $node->getFilename();
            if ('' == $regex || preg_match($regex, $name)) {
                $files[] = $name;
            }
        }
    }
    ksort($dirs);
    sort($files);
    return array_merge($dirs, $files);
}
?>
<body>
<pre>
<?=var_dump(dirtree(getcwd());?>
</pre>
</body>
</html>

这将为您完成工作。 但如上所述,更好的解决方案是分离目录和文件,如下所示:

<html>
<body>
<?php
class DirNode {
    public $name;
    public $dirs=[];
    public $files=[];

    public function DirNode($dirName) {
        $this->name = $dirName;
    }

    public function printDir($prefix="") {
        echo($prefix.$this->name."\n");
        foreach($this->dirs as $dir=>$subDir) {
            echo($prefix.$dir."\n");
            $subDir->printDir($prefix."    ");
            echo("\n");
        }
        foreach($this->files as $file) {
            echo($prefix.$file."\n");
        }
    }
}

function dirtree($dir, $regex = '', $ignoreEmpty = false)
{
    if (!$dir instanceof DirectoryIterator) {
        $dir = new DirectoryIterator((string) $dir);
    }
    $directory = new DirNode($dir);
    foreach ($dir as $node) {
        if ($node->isDir() && !$node->isDot()) {
            $tree = dirtree($node->getPathname(), $regex, $ignoreEmpty);
            if (!$ignoreEmpty || count($tree)) {
                $directory->dirs[$node->getFilename()] = $tree;
            }
        } elseif ($node->isFile()) {
            $name = $node->getFilename();
            if ('' == $regex || preg_match($regex, $name)) {
                $directory->files[] = $name;
            }
        }
    }
    ksort($directory->dirs);
    sort($directory->files);
    return $directory;
}

$dirfiles = dirtree(getcwd().'/..');

echo("<pre>");
echo($dirfiles->printDir());
echo("</pre>");

?>
</body>
</html>