使用VBA循环遍历所有子文件夹

47
我正在寻找一段VBA脚本,它将循环遍历指定文件夹的所有子文件夹。当我说所有子文件夹时,我指的是指定文件夹内的每个文件夹,以及每个文件夹中的每个文件夹,以此类推……理论上可能会有无限嵌套的子文件夹,但实际上可能不会超过3或4个。我使用VBA Scripting Runtime对象,因此一旦我进入文件夹,就可以检查一些文件的属性(但我知道如何完成这部分)。
感谢您的帮助!
此问题与先前列出的“相似”问题不同,因为之前的问题包含已知目录,而这里的需求是查找已知和未知目录。还需要多层子目录。在发出“重复”的回复之前,你们真的应该先阅读问题。

1
在这里,仅SO就有大量的示例-您尝试过搜索吗? - Tim Williams
3
这与Simoco发布的内容类似,但在那个例子中似乎有一个列表,而在这里,子文件夹在开始时是未知的-脚本需要找到它们。谢谢。 - Jake
1
是的,我已经尝试过搜索,但没有结果。感谢您的建议。 - Jake
2个回答

122

只是一个简单的文件夹逐级浏览。

sub sample()
    Dim FileSystem As Object
    Dim HostFolder As String

    HostFolder = "C:\"

    Set FileSystem = CreateObject("Scripting.FileSystemObject")
    DoFolder FileSystem.GetFolder(HostFolder)
end  sub

Sub DoFolder(Folder)
    Dim SubFolder
    For Each SubFolder In Folder.SubFolders
        DoFolder SubFolder
    Next
    Dim File
    For Each File In Folder.Files
        ' Operate on each file
    Next
End Sub

4
谢谢,我想这肯定是个简单的事情! - Jake
6
没问题,所有程序员在某个时候都会保留这个子文件夹“迭代”,这大多是复制和粘贴。别忘了给一个答案标记,我的朋友。 - Rich
3
为了完整性,下面添加了非递归方法 ;) - Cor_Blimey
2
你是否忘记定义某些东西了?对我来说不起作用 :( - mojo3340
3
我猜你不能只将SubFolder作为变量。它需要是Dim SubFolder as Object - hypers
显示剩余5条评论

52

为了补充Rich的递归答案,这里提供一个非递归方法。

Public Sub NonRecursiveMethod()
    Dim fso, oFolder, oSubfolder, oFile, queue As Collection

    Set fso = CreateObject("Scripting.FileSystemObject")
    Set queue = New Collection
    queue.Add fso.GetFolder("your folder path variable") 'obviously replace

    Do While queue.Count > 0
        Set oFolder = queue(1)
        queue.Remove 1 'dequeue
        '...insert any folder processing code here...
        For Each oSubfolder In oFolder.SubFolders
            queue.Add oSubfolder 'enqueue
        Next oSubfolder
        For Each oFile In oFolder.Files
            '...insert any file processing code here...
        Next oFile
    Loop

End Sub
你可以使用队列来实现FIFO行为(如上所示),或者你可以使用栈来实现LIFO行为,这将以与递归方法相同的顺序进行处理(用Set oFolder = queue(queue.Count)替换Set oFolder = queue(1),用queue.Remove(queue.Count)替换queue.Remove(1),并可能重命名变量...)

2
+1 这真是太酷了。我需要更多地了解集合。 - Rich
4
@Rich,这将会发生,但其他两个文件夹已经被储存在了集合中,在接下来的两次循环中我们会处理它们(不要忘记 queue.Remove 1 移除了第一个文件夹,所以第二个文件夹现在成为了集合的第一项,因此会在下一次调用 queue(1) 时被检索到)。栈的方法则相反,它总是操作最后添加的文件夹(用 queue(queue.Count) 替换 queue(1),用 queue.Remove queue.Count 替换 queue.Remove 1)。 - Cor_Blimey
3
在VBA中,集合非常有用,因为它们基本上是我们唯一的“列表”类型对象(也可以使用Scripting.Runtime中的键入字典)。您可以在处理某些内容时轻松地将结果添加到它们中,然后在最后将其转换为数组(这样可以节省使用Redim保留会每次循环进行数组复制的开销)。您可以使用它们查找独特值,映射值,在大量数据上进行快速查找等等。 - Cor_Blimey
4
我想指出,如果处理顺序对你很重要,那么这种方法将不能给出与递归方法相同的顺序。在这里,文件夹的处理顺序将如下所示:根目录根目录\子目录1根目录\子目录2根目录\子目录1\子目录1.1根目录\子目录1\子目录1.2根目录\子目录2\子目录2.1根目录\子目录2\子目录2.2......也就是说,文件夹按层级逐级处理。 - lapis
1
@Lapis 说得好。可以通过使用堆栈而不是队列(因此不是 x = queue(1): queue.remove 1,而是类似于 x = queue(queue.count): queue.remove(queue.count))以非递归的方式获得相同的顺序。 - Cor_Blimey
显示剩余4条评论

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