web-dev-qa-db-ja.com

VBAを使用してフォルダ内のファイルをループ処理する?

Excel 2010では vba を使用してディレクトリのファイルをループしたいと思います。

ループでは、私は必要になります

  • ファイル名
  • ファイルがフォーマットされた日付。

フォルダに50ファイル以下しかない場合はうまく動作するように、次のようにコーディングしました。それ以外の場合は、途方もなく遅くなります(> 10000ファイルのフォルダを処理するには必要です)。このコードの唯一の問題は、file.nameを検索する操作に非常に長い時間がかかることです。

動作するコードだがwaaaaaayが遅すぎる(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

解決した問題:

  1. 私の問題は、Dirを特定の方法(15000ファイルの場合は20秒)で使用し、コマンドFileDateTimeを使用してタイムスタンプをチェックすることで解決しました。
  2. 20秒未満からの別の回答を考慮に入れると、1秒未満に短縮されます。
216
tyrex

これが関数としての私の解釈です。

'#######################################################################
'# LoopThroughFiles
'# Function to Loop through files in current directory and return filenames
'# Usage: LoopThroughFiles ActiveWorkbook.Path, "txt" 'inputDirectoryToScanForFile
'# https://stackoverflow.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
35
benmichae2.

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
232
brettdj

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
153
grantnz

Dir関数を使用する方法がありますが、問題は、 ここ、下に向かって のように、Dir関数を再帰的に使用できないということです。

これを処理した方法は、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
24
LimaNightHawk

他のフォルダからファイルを処理して処理すると、Dir関数がフォーカスを失いやすくなります。

私はコンポーネントFileSystemObjectでより良い結果を得ました。

完全な例はここにあります:

http://www.xl-central.com/list-files-fso.html

Visual Basic Editorで参照を Microsoft Scripting Runtime に設定することを忘れないでください([ツール]> [参照]を使用)

試してみる!