【问题标题】:File info pull from sub folders only 2-3 levels deep从子文件夹中提取的文件信息只有 2-3 级
【发布时间】:2017-10-04 15:41:01
【问题描述】:

我目前有一个代码允许用户选择一个文件夹,然后该代码将提取该文件夹中文件的文件信息,但不会提取子文件夹中的任何文件。我有 7 个级别的子文件夹,包含大约 140,000 个文件。我想知道是否有办法让我只提取子文件夹级别 2-3 中的文件信息,而不仅仅是 1,也不是所有 7 个级别。感谢您的帮助。

我认为“第 3 列中的粘贴公式”部分与此问题无关。

可能重要的部分是“选择文件夹”和“遍历所选文件夹中的每个文件”

Sub Compile3()
  Dim oShell As Object
  Dim oFile As Object
  Dim oFldr As Object
  Dim lRow As Long
  Dim iCol As Integer
  Dim vArray As Variant
  vArray = Array(10, 0, 1, 156, 2, 4, 144, 146, 183, 185)

  Set oShell = CreateObject("Shell.Application")

  Dim iRow As Long
   iRow = Cells.find(What:="*", SearchOrder:=xlRows, SearchDirection:=xlPrevious, LookIn:=xlValues).Row
   lRow = iRow
'----------------------Picking a folder-------------------------------------


  With Application.FileDialog(msoFileDialogFolderPicker)
    .title = "Select the Folder..."
    If .Show Then
      Set oFldr = oShell.Namespace(.SelectedItems(1))
      With oFldr

      'Don't show update on the screen until the macro is finished
      Application.EnableEvents = False

'---------------Column header information-----------------------------------

        For iCol = LBound(vArray) To UBound(vArray)
          If lRow = 2 Then
            Cells(lRow, iCol + 4) = .getdetailsof(.items, vArray(iCol))
          Else
            Cells(lRow, iCol + 4) = "..."
          End If             
        Next iCol
'---------------Running through each file in the selected folder------------   
        For Each oFile In .items
          lRow = lRow + 1

          For iCol = LBound(vArray) To UBound(vArray)                   
             Cells(lRow, iCol + 4) = .getdetailsof(oFile, vArray(iCol))    
          Next iCol
 ' ---------------Pasting formula in column 3 -----------------------------             
               If lRow < 4 Then
                        Cells(lRow, 3).Formula = "=IFERROR(VLOOKUP(D3,$A$3:$B$10,2,FALSE),""User Not Found"")"

           Else
                    Cells((lRow - 1), 3).Copy
                    Cells(lRow, 3).PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
                    Cells(lRow, 3).PasteSpecial Paste:=xlPasteFormulas, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
                    Application.CutCopyMode = False                                       

           End If              
'------------------------------------------------------------------------------            

        Next oFile
      End With
    End If
Application.EnableEvents = True
  End With  

End Sub

【问题讨论】:

    标签: vba excel namespaces subdirectory createobject


    【解决方案1】:

    我修改了您的代码以使用数组并使用递归函数返回文件夹文件信息。


    Sub ProcessFolder()
        Dim FolderPath As String
        Dim results As Variant
        Dim Target As Range
    
        FolderPath = getFileDialogFolder
    
        If Len(FolderPath) = 0 Then Exit Sub
    
        getFolderItems FolderPath, results
        CompactResults results
    
        With Worksheets("Sheet1")
            .Range("C3", .Range("I" & Rows.Count).End(xlUp)).ClearContents
            Set Target = .Range("C3")
            Set Target = Target.EntireRow.Cells(1, 4)
            Target.Resize(UBound(results), UBound(results, 2)).Value = results
            Target.Offset(1, -1).Resize(UBound(results) - 1).Formula = "=IFERROR(VLOOKUP(D3,$A$3:$B$10,2,FALSE),""User Not Found"")"
        End With
    
    End Sub
    
    Sub CompactResults(ByRef results As Variant)
        Dim data As Variant
        Dim x As Long, x1 As Long, y As Long, y1 As Long
    
        ReDim data(1 To UBound(results) + 1, 1 To UBound(results(0)) + 1)
    
        For x = LBound(results) To UBound(results)
            x1 = x1 + 1
            y1 = 0
            For y = LBound(results(x)) To UBound(results(x))
                y1 = y1 + 1
                data(x1, y1) = results(x)(y)
            Next
        Next
    
        results = data
    End Sub
    
    Function getFileDialogFolder() As String
        With Application.FileDialog(msoFileDialogFolderPicker)
            .Title = "Select the Folder..."
            .AllowMultiSelect = False
            If .Show Then
                getFileDialogFolder = .SelectedItems(1)
            End If
        End With
    End Function
    
    Sub getFolderItems(FolderPath As String, ByRef results As Variant, Optional MaxLevels As Long = 1, Optional oShell As Object, Optional Level As Long)
        Dim oFile As Object, oFldr As Object
    
        If oShell Is Nothing Then
            ReDim results(0)
            Set oShell = CreateObject("Shell.Application")
        End If
    
        If Not IsEmpty(results(UBound(results))) Then ReDim Preserve results(UBound(results) + 1)
    
        Set oFldr = oShell.Namespace(CStr(FolderPath))
    
        results(UBound(results)) = getFolderFileDetailArray(oFldr.Self, oFldr)
        results(UBound(results))(1) = oFldr.Self.Path
        For Each oFile In oFldr.Items
            ReDim Preserve results(UBound(results) + 1)
            If oFldr.getDetailsOf(oFile, 2) = "File folder" Then
                If Level < MaxLevels Then
                    getFolderItems oFile.Path, results, MaxLevels, oShell, Level + 1
                End If
            End If
            results(UBound(results)) = getFolderFileDetailArray(oFile, oFldr)
        Next oFile
    
    End Sub
    
    Function getFolderFileDetailArray(obj As Object, oFldr As Object) As Variant
        Dim iCol As Integer
        Dim vDetailSettings As Variant
        vDetailSettings = Array(10, 0, 1, 156, 2, 4, 144, 146, 183, 185)
    
        For iCol = LBound(vDetailSettings) To UBound(vDetailSettings)
            vDetailSettings(iCol) = oFldr.getDetailsOf(obj, vDetailSettings(iCol))
        Next iCol
    
        getFolderFileDetailArray = vDetailSettings
    
    End Function
    

    【讨论】:

    • 感谢您的帮助。这看起来很有趣,但没有奏效。我在数组行上遇到错误:results = Application.Transpose(results) 我也不肯定你的代码会做我想做的事。这可能是不可能的。如上所述,我不只是想要“深潜”,而且我不只是想要第一级。 (我有 7 级文件夹,总共 140,000 个文件)我只想抓取 2-3 级信息。 (最好让用户确定深度多少级)
    • 所以它似乎不起作用。我已经有一个代码可以很好地提取第一个文件夹的文件信息。我想知道我是否可以获取特定级别的文件夹路径。这段代码能做到吗?
    • 是的。我不确定为什么它不适合你。
    • 您在代码中的哪个位置确定文件夹/文件拉取的深度?
    • 所以我打开了一个新的 excel 工作簿,并将您上面的内容粘贴到那里的模块中。我将Sub ProcessFolder() 连接到一个按钮。当我单击它时,它会拉出文件夹选择窗口。当我选择一个文件夹并点击 OK 时,什么也没有发生
    【解决方案2】:

    file system object 可以为您做到这一点。

    在此示例中,代码返回 C:\ 驱动器上的每个子文件夹。

    ' Returns every folder under the C:\.
    Sub CrawlFolder()
        Dim fso As FileSystemObject     ' Access the Windows file system.
        Dim folder As folder            ' Used to loop over folders.
    
    
        Set fso = New FileSystemObject
        For Each folder In fso.GetFolder("C:\").SubFolders
    
            Debug.Print folder.Name
        Next
    End Sub
    

    要查看结果,请确保您已打开 Immediate 窗口(查看 >> 即时窗口)。

    要使用文件系统对象,您需要添加一个引用(Tools >> References >> Windows 脚本宿主对象模型 )。

    您可以添加第二个For Each Loop 来查看文件:

    ' Returns every folder under the C:\.
    Sub CrawlFolder()
        Dim fso As FileSystemObject     ' Access the Windows file system.
        Dim folder As folder            ' Used to loop over folders.
        Dim file As file                ' Used to loop over files.
    
        Set fso = New FileSystemObject
        For Each folder In fso.GetFolder("C:\").SubFolders
    
            For Each file In folder.Files
    
                Debug.Print file.Name
            Next
        Next
    End Sub
    

    【讨论】:

    • 我看过使用FileSystemObject 的事情是它抓取C:\.. 驱动器中的所有子文件夹,并从这些子文件夹中抓取第二组和第三组子文件夹。然后,您的文件循环将抓取所有后续文件。我只想从最初的C:\. 驱动器下拉第一组和第二组文件和子文件夹,而不是第三组或第四组子文件夹
    • 这段代码只会返回一级文件夹(刚刚测试过Win7、Excel 2010)。确实fso可以用来深潜。这通常是使用称为recursion 的方法实现的,我在本示例中没有使用该方法。
    • 对,你可以修改它,但我想在中间做点什么。不是你所说的“深潜”,而不仅仅是第一级。 (我有 7 级文件夹,总共 140,000 个文件)我只想抓取 2-3 级信息
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    • 2019-03-22
    相关资源
    最近更新 更多