使用VBA循环浏览文件夹中的文件?
Posted
技术标签:
【中文标题】使用VBA循环浏览文件夹中的文件?【英文标题】:Loop through files in a folder using VBA? 【发布时间】:2012-05-09 22:53:19 【问题描述】:我想在 Excel 2010 中使用 vba 循环浏览目录的文件。
在循环中,我需要:
文件名和 文件格式化的日期。如果文件夹不超过 50 个文件,我已经编写了以下代码,它可以正常工作,否则速度会非常慢(我需要它来处理包含 >10000 个文件的文件夹)。这段代码的唯一问题是查找file.name
的操作非常耗时。
可以运行但速度太慢的代码(每 100 个文件 15 秒):
Sub LoopThroughFiles()
Dim MyObj As Object, MySource As Object, file As Variant
Set MySource = MyObj.GetFolder("c:\testfolder\")
For Each file In MySource.Files
If InStr(file.name, "test") > 0 Then
MsgBox "found"
Exit Sub
End If
Next file
End Sub
问题已解决:
-
我的问题已通过以下解决方案解决,该解决方案使用
Dir
以特定方式(15000 个文件为 20 秒)并使用命令FileDateTime
检查时间戳。
考虑到 20 秒以下的另一个答案,将缩短到不到 1 秒。
【问题讨论】:
对于 VBA,您的初始时间似乎仍然很慢。你在使用 Application.ScreenUpdating=false 吗? 你好像不见了code
Set MyObj = New FileSystemObject
我发现人们很快就将 FSO 称为“慢”,这很让人难过,但是没有人提到通过简单地使用早期绑定而不是针对Object
的后期绑定调用可以避免的性能损失。
【参考方案1】:
Dir
采用通配符,因此您可以为test
预先添加过滤器并避免测试每个文件
Sub LoopThroughFiles()
Dim StrFile As String
StrFile = Dir("c:\testfolder\*test*")
Do While Len(StrFile) > 0
Debug.Print StrFile
StrFile = Dir
Loop
End Sub
【讨论】:
太棒了。这只是将运行时间从 20 秒提高到 这可能是因为 Do while...loop 比 while...wend 更好。更多信息在这里***.com/questions/32728334/… 我认为没有那个改进水平(20 - xxx 次) - 我认为通配符会有所作为。 DIR() 似乎没有返回隐藏文件。 @hamish,您可以更改其参数以返回不同类型的文件(隐藏、系统等) - 请参阅 MS 文档:docs.microsoft.com/en-us/office/vba/language/reference/…【参考方案2】:Dir 似乎很快。
Sub LoopThroughFiles()
Dim MyObj As Object, MySource As Object, file As Variant
file = Dir("c:\testfolder\")
While (file <> "")
If InStr(file, "test") > 0 Then
MsgBox "found " & file
Exit Sub
End If
file = Dir
Wend
End Sub
【讨论】:
太好了,非常感谢。我确实使用 Dir,但我不知道您也可以这样使用它。除了命令FileDateTime
,我的问题也解决了。
还有一个问题。如果 DIR 从最近的文件开始循环,我可以大大提高速度。你觉得有什么办法吗?
我的后一个问题已由 brettdj 下面的评论解决。
目录将not
但是traverse the whole directory tree
。如有需要:analystcave.com/vba-dir-function-how-to-traverse-directories/…
Dir 也会被其他 Dir 命令打断,所以如果你运行一个包含 Dir 的子程序,它可以在你原来的子程序中“重置”它。根据原始问题使用 FSO 可以消除此问题。编辑:刚刚看到下面@LimaNightHawk 的帖子,同样的事情【参考方案3】:
这是我作为函数的解释:
'#######################################################################
'# LoopThroughFiles
'# Function to Loop through files in current directory and return filenames
'# Usage: LoopThroughFiles ActiveWorkbook.Path, "txt" 'inputDirectoryToScanForFile
'# https://***.com/questions/10380312/loop-through-files-in-a-folder-using-vba
'#######################################################################
Function LoopThroughFiles(inputDirectoryToScanForFile, filenameCriteria) As String
Dim StrFile As String
'Debug.Print "in LoopThroughFiles. inputDirectoryToScanForFile: ", inputDirectoryToScanForFile
StrFile = Dir(inputDirectoryToScanForFile & "\*" & filenameCriteria)
Do While Len(StrFile) > 0
Debug.Print StrFile
StrFile = Dir
Loop
End Function
【讨论】:
为什么函数,什么时候没有返回?这和 brettdj 给出的答案不一样,只是它包含在一个函数中【参考方案4】:Dir 函数是可行的方法,但问题是您不能递归地使用Dir
函数,如here, towards the bottom 所述。
我处理这个问题的方法是使用Dir
函数来获取目标文件夹的所有子文件夹并将它们加载到一个数组中,然后将该数组传递给一个递归函数。
这是我编写的一个完成此任务的类,它包括搜索过滤器的能力。 (你必须原谅匈牙利符号,这是在它风靡一时的时候写的。)
Private m_asFilters() As String
Private m_asFiles As Variant
Private m_lNext As Long
Private m_lMax As Long
Public Function GetFileList(ByVal ParentDir As String, Optional ByVal sSearch As String, Optional ByVal Deep As Boolean = True) As Variant
m_lNext = 0
m_lMax = 0
ReDim m_asFiles(0)
If Len(sSearch) Then
m_asFilters() = Split(sSearch, "|")
Else
ReDim m_asFilters(0)
End If
If Deep Then
Call RecursiveAddFiles(ParentDir)
Else
Call AddFiles(ParentDir)
End If
If m_lNext Then
ReDim Preserve m_asFiles(m_lNext - 1)
GetFileList = m_asFiles
End If
End Function
Private Sub RecursiveAddFiles(ByVal ParentDir As String)
Dim asDirs() As String
Dim l As Long
On Error GoTo ErrRecursiveAddFiles
'Add the files in 'this' directory!
Call AddFiles(ParentDir)
ReDim asDirs(-1 To -1)
asDirs = GetDirList(ParentDir)
For l = 0 To UBound(asDirs)
Call RecursiveAddFiles(asDirs(l))
Next l
On Error GoTo 0
Exit Sub
ErrRecursiveAddFiles:
End Sub
Private Function GetDirList(ByVal ParentDir As String) As String()
Dim sDir As String
Dim asRet() As String
Dim l As Long
Dim lMax As Long
If Right(ParentDir, 1) <> "\" Then
ParentDir = ParentDir & "\"
End If
sDir = Dir(ParentDir, vbDirectory Or vbHidden Or vbSystem)
Do While Len(sDir)
If GetAttr(ParentDir & sDir) And vbDirectory Then
If Not (sDir = "." Or sDir = "..") Then
If l >= lMax Then
lMax = lMax + 10
ReDim Preserve asRet(lMax)
End If
asRet(l) = ParentDir & sDir
l = l + 1
End If
End If
sDir = Dir
Loop
If l Then
ReDim Preserve asRet(l - 1)
GetDirList = asRet()
End If
End Function
Private Sub AddFiles(ByVal ParentDir As String)
Dim sFile As String
Dim l As Long
If Right(ParentDir, 1) <> "\" Then
ParentDir = ParentDir & "\"
End If
For l = 0 To UBound(m_asFilters)
sFile = Dir(ParentDir & "\" & m_asFilters(l), vbArchive Or vbHidden Or vbNormal Or vbReadOnly Or vbSystem)
Do While Len(sFile)
If Not (sFile = "." Or sFile = "..") Then
If m_lNext >= m_lMax Then
m_lMax = m_lMax + 100
ReDim Preserve m_asFiles(m_lMax)
End If
m_asFiles(m_lNext) = ParentDir & sFile
m_lNext = m_lNext + 1
End If
sFile = Dir
Loop
Next l
End Sub
【讨论】:
如果我想列出在列中找到的文件,这可能是什么实现? @jechaviz GetFileList 方法返回一个字符串数组。您可能只是遍历数组并将项目添加到 ListView 或类似的东西。有关如何在列表视图中显示项目的详细信息可能超出了本文的范围。【参考方案5】:Dir
函数在我处理和处理其他文件夹中的文件时很容易失去焦点。
我使用组件 FileSystemObject
获得了更好的结果。
这里给出了完整的例子:
http://www.xl-central.com/list-files-fso.html
不要忘记在 Visual Basic 编辑器中设置对 Microsoft 脚本运行时的引用(通过使用工具 > 引用)
试一试!
【讨论】:
从技术上讲,这是提问者使用的方法,他们只是没有包含他们的参考资料,这会减慢这种方法的速度。【参考方案6】:试试这个。 (LINK)
Private Sub CommandButton3_Click()
Dim FileExtStr As String
Dim FileFormatNum As Long
Dim xWs As Worksheet
Dim xWb As Workbook
Dim FolderName As String
Application.ScreenUpdating = False
Set xWb = Application.ThisWorkbook
DateString = Format(Now, "yyyy-mm-dd hh-mm-ss")
FolderName = xWb.Path & "\" & xWb.Name & " " & DateString
MkDir FolderName
For Each xWs In xWb.Worksheets
xWs.Copy
If Val(Application.Version) < 12 Then
FileExtStr = ".xls": FileFormatNum = -4143
Else
Select Case xWb.FileFormat
Case 51:
FileExtStr = ".xlsx": FileFormatNum = 51
Case 52:
If Application.ActiveWorkbook.HasVBProject Then
FileExtStr = ".xlsm": FileFormatNum = 52
Else
FileExtStr = ".xlsx": FileFormatNum = 51
End If
Case 56:
FileExtStr = ".xls": FileFormatNum = 56
Case Else:
FileExtStr = ".xlsb": FileFormatNum = 50
End Select
End If
xFile = FolderName & "\" & Application.ActiveWorkbook.Sheets(1).Name & FileExtStr
Application.ActiveWorkbook.SaveAs xFile, FileFormat:=FileFormatNum
Application.ActiveWorkbook.Close False
Next
MsgBox "You can find the files in " & FolderName
Application.ScreenUpdating = True
End Sub
【讨论】:
以上是关于使用VBA循环浏览文件夹中的文件?的主要内容,如果未能解决你的问题,请参考以下文章
使用循环打开文件路径中的所有excel文件后,有没有办法通过vba创建工作簿变量来引用这些文件?
访问中的 Vba 代码循环遍历文件夹中的所有 excel 文件,打开、保存和关闭它们