Home > Software design >  Loop FASTER through folders, subfolders and collect file names path VBA
Loop FASTER through folders, subfolders and collect file names path VBA

Time:12-11

i tryed few codes, but they works too slow. We have like half million files in server which i need to loop. And result is like only 3-4 k in 5 mins :) Maybe you guys idea how to do this code loop faster? thank you in advance

Option Explicit
Sub getfiles()

    Dim oFSO As Object
    Dim oFolder As Object
    Dim oFile As Object, sf
    Dim i As Integer, colFolders As New Collection, ws As Worksheet, y As Integer
    
    Set ws = ActiveSheet
    Set oFSO = CreateObject("Scripting.FileSystemObject")
    Set oFolder = oFSO.GetFolder('my path)
    
    colFolders.Add oFolder
    
    DoEvents
    Do While colFolders.Count > 0
        Set oFolder = colFolders(1)
        colFolders.Remove 1
    
        For Each oFile In oFolder.Files
            If Right(oFile.Name, 4) = ".pdf" Then
                ws.Cells(i   1, 1) = oFolder.Path
                ws.Cells(i   1, 2) = oFile.Name
                i = i   1
                y = y   1
                If y = 2000 Then 'just saving to check result after few minutes with pause
                    ThisWorkbook.Save
                    Application.Wait (Now   TimeValue("0:00:10"))
                    y = 0
                End If
            End If
        Next oFile
        For Each sf In oFolder.SubFolders
            colFolders.Add sf
        Next sf
    Loop

End Sub

CodePudding user response:

This should be faster:

Option Explicit

Sub getPdfFiles()
    'perf question from https://stackoverflow.com/questions/70304602/loop-faster-through-folders-subfolders-and-collect-file-namespath-vba
'    Dim startTime As Date: startTime = Now()
'    Debug.Print "start: " & Format(startTime, "hh:mm:ss")
    
    Dim i As Integer, ws As Worksheet, y As Integer
    
    Set ws = ActiveSheet
    
    Dim output As Object
    Set output = ShellOutput("Dir D:\BYoung\*.pdf /s /b")
    
    Dim inLines() As String
    ReDim inLines(1 To 1)
    Dim sLine As String, lines As Long
    
    DoEvents
    Do While Not output.AtEndOfStream
        sLine = output.ReadLine
    
        If Right(sLine, 4) = ".pdf" Then
            ReDim Preserve inLines(1 To i   1)
            i = i   1
            ReDim Preserve inLines(1 To i)
            inLines(i) = sLine
        End If
        If i Mod 100 = 0 Then DoEvents
    Loop
    lines = i
    
    Dim fName As String, fFull As String, fPath As String
    Dim outLines As Variant
    ReDim outLines(1 To lines, 1 To 2)
    
    For i = 1 To lines
        fFull = inLines(i)
        fName = Right(fFull, Len(fFull) - InStrRev(fFull, "\"))
        fPath = Mid(fFull, 1, Len(fFull) - Len(fName))
        outLines(i, 1) = fPath
        outLines(i, 2) = fName
        If i Mod 100 = 0 Then DoEvents
    Next i
    
    ws.Range("A1:B" & lines) = outLines
    
    ThisWorkbook.Save
    
    'Dim doneTime As Date: doneTime = Now()
    'Debug.Print "done: " & Format(doneTime, "hh:mm:ss")
End Sub

Which calls this function:

' Create a Shell, executes a command, and returns the output stream
Public Function ShellOutput(sCmd As String) As Object
    Dim oShell As Object
    Set oShell = CreateObject("WScript.Shell")

    'run command
    Dim oExec As Object
    Dim oOutput As Object
    Set oExec = oShell.Exec("cmd.exe /c " & sCmd)
    Set oOutput = oExec.StdOut

    Set ShellOutput = oOutput
End Function

CodePudding user response:

Another option using Dir() for files:


Sub Tester()
   Dim matches As Collection
   
   Set matches = GetMatches("C:\Test", "*.pdf")

   'loop matches and list file info...
    
End Sub


'Return a collection of file objects given a starting folder and a file pattern
'  e.g. "*.txt"
'Pass False for last parameter if don't want to check subfolders
Function GetMatches(startFolder As String, filePattern As String, _
                    Optional subFolders As Boolean = True) As Collection

    Dim fso, fldr, f, subFldr, fpath
    Dim colFiles As New Collection
    Dim colSub As New Collection
    
    Set fso = CreateObject("scripting.filesystemobject")
    colSub.Add startFolder
    
    Do While colSub.Count > 0
        
        Set fldr = fso.getfolder(colSub(1))
        colSub.Remove 1
        
        If subFolders Then
            For Each subFldr In fldr.subFolders
                colSub.Add subFldr.Path
            Next subFldr
        End If
        
        fpath = fldr.Path
        If Right(fpath, 1) <> "\" Then fpath = fpath & "\"
        f = Dir(fpath & filePattern)'Dir is faster...
        Do While Len(f) > 0
            colFiles.Add fso.getfile(fpath & f)
            f = Dir()
        Loop
    Loop
    Set GetMatches = colFiles
End Function
  • Related