无法正确递归目录

时间:2019-06-14 05:20:00

标签: c++ qt

我正在尝试使用QT创建器应用程序创建的C ++程序中的目录递归。出于某种原因,QDir :: entryList和QDirIterator都无法正常工作。使用QDirIterator,我可以找到第二个目录,但是没有更多。当我将QDir :: entryList与嵌套的foreach循环一起使用时,也会发生类似的情况。最终,我希望获得目录链中的最后一个目录,其中不包含其他目录。

这旨在成为跨平台的,因此它不能特定于操作系统。我还希望避免为不同的OS使用大量开关,因为我不想以后再使用它,而只需使用它(可能永远使用)。我尝试过foreach循环,while循环,这是我能想到的。

QDir代码:

QStringList GetLastSubDirs(QDir baseDirectory) {
        QStringList result;
        baseDirectory.setFilter( QDir::Dirs|QDir::NoDotAndDotDot );
        QStringList nonEmptyDirs(baseDirectory.path());
        while (nonEmptyDirs.size() > 0) {
            foreach (QString d, nonEmptyDirs) {
                QDir sd(d);
                foreach (QDir checkingDir, sd.entryList(QDir::Dirs|QDir::NoDotAndDotDot)) {
                    if (checkingDir.entryList().size() == 0) {
                       result.append(checkingDir.path());
                    } else {
                        nonEmptyDirs.append(checkingDir.path());
                    }
                }
                nonEmptyDirs.removeOne(d);
            }
        }
        if (result.size() == 0) {
            result = QStringList(baseDirectory.path());
        }
        return result;
    }
};

这是QDirIterator代码:

class Directories
{
public:
        QStringList GetLastSubDirs(QDir baseDirectory) {
        QStringList result;
        baseDirectory.setFilter( QDir::Dirs|QDir::NoDotAndDotDot );
        QDirIterator it(QDir::currentPath() + "/" + baseDirectory.path(), QDirIterator::Subdirectories);
        while(it.hasNext()) {
            QDir curWorkDir(it.path());
            curWorkDir.setFilter( QDir::Dirs|QDir::NoDot|QDir::NoDotDot );
            if(curWorkDir.entryList().size() >= 1) {
                foreach (QDir d, curWorkDir.entryList()) {
                    d.setFilter( QDir::Dirs|QDir::NoDot|QDir::NoDotDot );
                    if (d.entryList().size() <= 0) {
                        result.append(d.path());
                    }
                }
            } else {
                result.append(curWorkDir.path());
            }
            it.next();
        }
        if (result.size() == 0) {
            result = QStringList(baseDirectory.path());
        }
        return result;
    }
};

调试器输出

1 Directories::GetLastSubDirs               main.cpp     56  0x555555559ba9 
2 Games::Games                              main.cpp     80  0x555555559f98 
3 __static_initialization_and_destruction_0 main.cpp     104 0x55555555931b 
4 _GLOBAL__sub_I_main.cpp(void)             main.cpp     120 0x55555555934e 
5 __libc_csu_init                                            0x55555555cd9d 
6 __libc_start_main                         libc-start.c 247 0x7ffff54ed270 
7 _start                                                     0x555555558f2a 

反汇编程序输出:

0x555555558f00                  31 ed                 xor    %ebp,%ebp
0x555555558f02  <+    2>        49 89 d1              mov    %rdx,%r9
0x555555558f05  <+    5>        5e                    pop    %rsi
0x555555558f06  <+    6>        48 89 e2              mov    %rsp,%rdx
0x555555558f09  <+    9>        48 83 e4 f0           and    $0xfffffffffffffff0,%rsp
0x555555558f0d  <+   13>        50                    push   %rax
0x555555558f0e  <+   14>        54                    push   %rsp
0x555555558f0f  <+   15>        4c 8d 05 aa 3e 00 00  lea    0x3eaa(%rip),%r8        # 0x55555555cdc0 <__libc_csu_fini>
0x555555558f16  <+   22>        48 8d 0d 33 3e 00 00  lea    0x3e33(%rip),%rcx        # 0x55555555cd50 <__libc_csu_init>
0x555555558f1d  <+   29>        48 8d 3d 74 01 00 00  lea    0x174(%rip),%rdi        # 0x555555559098 <main(int, char**)>
0x555555558f24  <+   36>        ff 15 c6 70 20 00     callq  *0x2070c6(%rip)        # 0x55555575fff0
0x555555558f2a  <+   42>        f4                    hlt

我希望这个特定的代码片段可以递归目录,直到清除包含其他目录的任何目录为止。相反,它只会下降一个级别并停止。出于某些原因,在查询这些目录的entryList()。size()时,即使目录包含其他目录,它也始终返回0,除非我包含...,然后它才循环永远,因为它不打算那样处理。

3 个答案:

答案 0 :(得分:1)

我不知道你为什么这么复杂。 documentation说:

QDirIterator类为目录条目列表提供了一个迭代器。

您可以使用QDirIterator一次浏览一个目录条目。它与QDir :: entryList()和QDir :: entryInfoList()相似,但是由于它一次列出一个条目,而不是一次列出所有条目,因此扩展性更好,更适合大型目录。它还支持递归列出目录内容以及跟随符号链接。与QDir :: entryList()不同,QDirIterator不支持排序。

QDirIterator构造函数将QDir或目录作为参数。构造之后,迭代器位于第一个目录条目之前。以下是顺序遍历所有条目的方法:

QDirIterator it("/etc", QDirIterator::Subdirectories);
while (it.hasNext()) {
    qDebug() << it.next();

    // /etc/.
    // /etc/..
    // /etc/X11
    // /etc/X11/fs
    // ...
}

在提供QDirIterator :: Subdirectories时,QDirIterator已经是递归的。

答案 1 :(得分:0)

QDir::EntryList返回子条目的名称,而不是其完整路径。您需要将名称附加到父路径以获取完整路径。

给出层次结构:

  basedir/
     child1/
     child2/
        grandchild1/
        grandchild2/

entryList上调用baseDir将返回["child1", "child2"],而不是["basedir/child1", "basedir/child2"]


正如我在评论中所说:即使您解决了该问题,我也不希望这段代码能正常工作。您正在nonEmptyDirs的{​​{1}}循环内修改foreach。感觉很危险。它肯定不会在C ++ 11的for-for循环中工作。我建议手动写出foreach宏以检查它是否可以工作。特别是,删除当前迭代器指向的列表中的条目并不能很好地结束。

答案 2 :(得分:0)

Qt documentation ...最重要的最后一句话开始

  

Qt在进入foreach循环时会自动获取该容器的副本。如果在迭代时修改容器,则不会影响循环。 (如果不修改容器,则仍会进行复制,但是由于隐式共享,复制容器非常快。)

     

由于foreach创建了容器的副本,因此对变量使用非常量引用将不允许您修改原始容器。它只会影响副本,这可能不是您想要的。