多维数组目录映射

3
我将尝试将目录结构转化为多维数组。
我已经完成了以下步骤:
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等。 这似乎是由于我的目录具有数字名称导致的?

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
        )

你能在这里添加 var_dump $dirs$files 和期望的输出吗? - Prafulla Kumar Sahu
哦,array_merge 怎么会不起作用呢?当我运行你的代码时,我得到了按名称键入的目录,就像预期的那样。array_merge 应该保留字符串键... - Roger Gee
显然,这是因为我的目录名称是数字... 现在才意识到,感谢评论提醒,否则我会把它放在问题中。 - Alex
array_merge() 的情况下,数字键将在合并过程中递增。这意味着您可以通过检查映射值是标量还是数组来检测目录与常规文件之间的区别。例如,如果读取到目录 0,那么第一个文件将被键入 1。您可以通过检查 $result[0] 是否为数组或标量来区分它们。 - Roger Gee
3个回答

3
解决方案非常简单,感谢合并数组而不丢失键索引
不要使用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;
}

谢谢分享解决方案,我一直在尝试找到一个。你的文件夹名称是数字名称,对吗? - Accountant م
他们确实这样做了,现在你提到了,那些是唯一没有起作用的,这可能是最初的原因。 - Alex
@RogerGee 我的目录(至少是这个操作中涉及到的那些)都有唯一的数字名称,比如123456和123457等。尽管它们是数字,但似乎没有任何缺失的文件? - Alex
你可以考虑为常规文件设置一个特殊的桶。请参阅我的答案。如果不太麻烦,您始终可以通过映射到数组的键来过滤键。 - Roger Gee
我所看到的更新解决方案唯一的问题是读取目录条目的顺序。如果首先读取一个常规文件,然后是名为0的目录,则文件条目将被覆盖。 - Roger Gee
显示剩余5条评论

1
使用数组合并操作是危险的,因为您可能会覆盖现有文件。请考虑以下目录结构:
a       <-- directory
├── 0   <-- directory (empty)
├── b   <-- regular file
└── c   <-- directory
    └── d   <-- regular file

现在考虑使用数组并集来运行该操作。我得到了以下结果:
array(2) {
  [0]=>
  array(0) {
  }
  ["c"]=>
  array(1) {
    [0]=>
    string(1) "d"
  }
}

请注意,常规文件b不存在?这是因为数组联合操作优先使用现有的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;
}

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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接