2016-09-07 88 views
0

给出的例子目录树来进行测试:Visual Studio recursive_directory_iterator.pop()是否被破坏?

Root 
    A 
     A1 
     A2 
    B 
     B1 
     B2 

我想递归地列举目录,但完全跳过目录A的处理。

根据MSDN文档代码类似于下面的东西应该做的工作:

void TestRecursion1() 
{ 
    path directory_path("Root"); 
    recursive_directory_iterator it(directory_path); 

    while (it != recursive_directory_iterator()) 
    { 
     if (it->path().filename() == "A") 
     { 
     it.pop(); 
     } 
     else 
     { 
     ++it; 
     } 
    } 
} 

...事实并非如此。 MSDN的recursive_directory_iterator.pop()指出

If depth() == 0 the object becomes an end-of-sequence iterator. 
Otherwise, the member function terminates scanning of the current 
(deepest) directory and resumes at the next lower depth. 

实际发生的是,由于在流行短路试验(+),如果“深度== 0”无任何响应,迭代器既不增加也不它成为序列迭代器的终点,程序进入无限循环。

这个问题似乎是在语义上弹出()是为了将树的处理分流到高于当前级别的下一级,而在本例中我希望跳过A的处理并继续在B处处理。第一个问题是这两个目录(A和B)存在于树中的同一级别,第二个问题是该级别也是树的最高级别,所以没有更高的级别来恢复处理。尽管如此,它仍然像是一个bug,pop()未能将迭代器设置为序列结束迭代器,从而导致无限循环。

经过这次测试,我推断如果我不能直接弹出()A,我应该至少能够从A的任何子节点弹出()并获得类似的结果。我用下面的代码测试此:

template<class TContainer> 
bool begins_with(const TContainer& input, const TContainer& match) 
{ 
    return input.size() >= match.size() 
     && equal(match.begin(), match.end(), input.begin()); 
} 

void TestRecursion2() 
{ 
    path base_path("C:\\_Home\\Development\\Workspaces\\Scratch \\TestDirectoryRecursion\\bin\\Debug\\Root"); 
    recursive_directory_iterator it(base_path); 

    while (it != recursive_directory_iterator()) 
    { 
     string relative_path = it->path().parent_path().string().substr(base_path.string().size()); 
     cout << relative_path << "\n"; 

     if (begins_with(relative_path, string("\\A"))) 
     { 
     it.pop(); 
     } 
     else 
     { 
     cout << it->path().filename() << " depth:" << it.depth() << "\n"; 
     ++it; 
     } 
    } 
} 

在这里,我测试正在处理每一个项目,以确定其是否父是root \ A,如果是调用pop()方法。即使这不起作用。测试正确地标识了树中的一个节点是否是A的子节点,并相应地调用pop(),但即使在更深层次上,pop()仍然无法增加迭代器,从而导致无限循环。更重要的是,即使这个做了的工作,它仍然是非常不受欢迎的,因为不能保证枚举子节点的顺序,所以尽管测试检查特定节点是否是A的子节点,因为这些节点可能作为间接的孩子,你仍然可以最终处理好数量的A。

我认为我的下一步行动是放弃使用此recursive_directory_iterator并使用标准directory_iterator手动驱动递归,但似乎我应该能够实现我更需要recursive_directory_iterator的简单功能,每一次都会被挡住。所以我的问题是:

是否recursive_directory_iterator.pop()方法被破坏?

如果不是我如何使用它来跳过处理目录?

回答

0

是不是你想要的代码更像以下,使用disable_recursion_pending()

while (it != recursive_directory_iterator()) 
    { 
     if (it->path().filename() == "A") 
     { 
     it.disable_recursion_pending(); 
     } 
     ++it; 
    } 
+0

这的确行得通,但disable_recursion_pending仅在VS2015中可用,我试图在VS2012中做到这一点。 disable_recursion_pending的文档声明它“在no_push中存储true”,VS2012有一个no_push方法,但其效果是禁止每个后续树节点的递归,而不仅仅是您调用它的那个节点。这似乎也完全破坏了,因为这不是tr2文件系统库所基于的Boost实现的行为。在Boost实现中,no_push只适用于迭代器当前指向的节点。 – Neutrino

+0

您引用的'pop()'的描述是针对VS2015的 - 对VS2012的'pop()'的描述只是说“停止读取当前子目录并递增迭代器” - 不保证随后会发生什么。 – Jeremy

+0

你说得对,我在VS2012和VS2015测试了这个,我从错误的页面复制了文档片段。尽管如此,它仍然不会增加VS2012中的迭代器。 – Neutrino