【问题标题】:Extract file names from a File Explorer search into Excel从文件资源管理器搜索中提取文件名到 Excel
【发布时间】:2020-12-01 23:32:35
【问题描述】:

这一直困扰着我,因为我觉得我的拼图很少,但我无法将它们全部放在一起

所以我的目标是能够在给定位置的所有 .pdf 文件中搜索文件内容中的关键字或短语,而不是文件名,然后使用搜索结果填充 Excel 电子表格。

在我们开始之前,我知道使用 Acrobat Pro API 很容易做到这一点,但我的公司不会为每个人支付许可证费用以使这个宏能够正常工作。

windows 文件资源管理器搜索接受高级查询语法,并将在文件内容中搜索,前提是启用了正确的 ifilter。例如。如果您有一个名为 doc1.docx 的 word 文档,并且文档中的文本为“blahblahblah”,并且您搜索“blah”,则结果将显示 doc1.docx。 据我所知,使用 FileSystemObject 无法实现这一点,但如果有人可以确认任何一种方式真的有用吗?

我有一个简单的代码,可以打开一个资源管理器窗口并在给定位置的所有文件的内容中搜索一个字符串。搜索完成后,我有一个资源管理器窗口,其中列出了所有需要的文件。 如何获取此列表并使用这些文件的文件名填充 Excel?

dim eSearch As String
eSearch = "explorer " & Chr$(34) & "search-ms://query=System.Generic.String:" & [search term here] & "&crumb=location:" & [Directory Here] & Chr$(34)
Call Shell (eSearch)

【问题讨论】:

    标签: excel vba pdf


    【解决方案1】:

    我已经忘记了有关 VBA 的所有知识,但最近偶然发现了一种使用 Shell.Application COM 对象执行资源管理器搜索的简单方法。我的代码是 PowerShell,但 COM 对象和方法才是关键。这里肯定有人会翻译。

    我认为这有几个优点:

    1. 查询文本与您在 Explorer 的搜索栏中输入的内容相同,例如'Ext:pdf Content:compressor'

    2. 它很容易从代码启动,结果很容易用代码提取,但SearchResults窗口可用于目视检查/审查。

    3. 通过循环和暂停,您可以在同一个窗口中执行一系列搜索。

    我认为这种能力一直存在,但是 Document 对象和 FilterView 方法的 MS 文档没有提及它们如何应用于文件资源管理器

    我希望其他人觉得这很有用。

    $FolderToSearch = 'c:\Path\To\Folder'
    $SearchBoxText  = 'ext:pdf Content:compressor'
    
    $Shell = New-Object -ComObject shell.application
    
    ###  Get handles of currenlty open Explorer Windows
    $CurrentWindows = ( $Shell.Windows() | Where FullName -match 'explorer.exe$' ).HWND
    
    $WinCount = $Shell.Windows().Count
    $Shell.Open( $FolderToSearch )
    
    Do { Sleep -m 50 } Until ( $Shell.Windows().Count -gt $WinCount )
    
    $WindowToSerch = ( $Shell.Windows() | Where FullName -match 'explorer.exe$' ) | Where { $_.HWND -notIn $CurrentWindows }
    
    $WindowToSearch.Document.FilterView( $SearchBoxText )
    
    Do { Sleep -m 50 } Until ( $WindowToSearch.ReadyState -eq 4 )
    
    ### Fully-qualified name:
    $FoundFiles = ( $WindowToSearch.Document.Folder.Items() ).Path
    ### or just the filename:
    $FoundFiles = ( $WindowToSearch.Document.Folder.Items() ).Name
    
    ### $FoundFIles is an array of strings containing the names.
    ### The Excel portion I leave to you! :D
    

    【讨论】:

      【解决方案2】:

      请尝试使用下一个功能:

      Function GetFilteredFiles(foldPath As String) As Collection
          'If using a reference to `Microsoft Internet Controls (ShDocVW.dll)_____________________
          'uncomment the next 2 lines and comment the following three (without any reference part)
          'Dim ExpWin As SHDocVw.ShellWindows, CurrWin As SHDocVw.InternetExplorer
          'Set ExpWin = New SHDocVw.ShellWindows
          '_______________________________________________________________________________________
          'Without any reference:_____________________________________
          Dim ExpWin As Object, CurrWin As Object, objshell As Object
          Set objshell = CreateObject("Shell.Application")
          Set ExpWin = objshell.Windows
          '___________________________________________________________
          Dim Result As New Collection, oFolderItems As Object, i As Long
      
          Dim CurrSelFile As String
          For Each CurrWin In ExpWin
              If Not CurrWin.Document Is Nothing Then
                  If Not CurrWin.Document.FocusedItem Is Nothing Then
                      If left(CurrWin.Document.FocusedItem.Path, _
                          InStrRev(CurrWin.Document.FocusedItem.Path, "\")) = foldPath Then
                      
                          Set oFolderItems = CurrWin.Document.folder.Items
                          For i = 0 To oFolderItems.count
                              On Error Resume Next
                                If Err.Number <> 0 Then
                                   Err.Clear: On Error GoTo 0
                                Else
                                   Result.Add oFolderItems.item(CLng(i)).Name
                                   On Error GoTo 0
                                End If
                          Next
                      End If
                  End If
              End If
          Next CurrWin
          Set GetFilteredFiles = Result
      End Function
      
      

      就像这样,该函数无需任何参考即可工作......

      上述函数必须在您在现有代码中执行搜索查询后调用。可以通过下一种(测试)方式调用:

      Sub testGetFilteredFiles()
        Dim C As Collection, El As Variant
        Set C = GetFilteredFiles("C:\Teste VBA Excel\")'use here the folder path you used for searching
        For Each El In C
          Debug.Print El
        Next
      End Sub
      

      上述解决方案在所有IExplorer 窗口之间迭代,并返回那里可见的内容(过滤后)您最初用于搜索的文件夹

      您可以手动测试它,在特定文件夹中搜索某些内容,然后使用该特定文件夹路径作为参数调用函数("\" 末尾的反斜杠...)。

      【讨论】:

        【解决方案3】:

        假设位置已编入索引,您可以使用 ADO 直接访问目录(添加对 Microsoft ActiveX Data Objects 2.x 的引用):

        Dim cn  As New ADODB.Connection
        Dim rs  As New ADODB.Recordset
        Dim sql As String
        
        cn.Open "Provider=Search.CollatorDSO;Extended Properties='Application=Windows'"
        
        sql = "SELECT System.ItemNameDisplay, System.ItemPathDisplay FROM SystemIndex WHERE SCOPE='file:C:\look\here' AND System.Kind <> 'folder' AND CONTAINS(System.FileName, '""*.PDF""') AND CONTAINS ('""find this text""')"
        
        rs.Open sql, cn, adOpenForwardOnly, adLockReadOnly
        
        If Not rs.EOF Then
            Do While Not rs.EOF
                Debug.Print "File: "; rs.Collect(0)
                Debug.Print "Path: "; rs.Collect(1)
                rs.MoveNext
            Loop
        End If
        

        【讨论】:

        • 嗨亚历克斯,这非常有用,我自己不会找到那个解决方案!这是我尝试做的更简单的实现!我需要等待我的系统管理员将所需的文件夹添加到索引位置,我会尽快回复您。再次感谢!
        • 这看起来很有趣!但我想不出它来测试一个特定的案例。如果我尝试在文件夹C:MyTestFolder 中查找名称为Test*.xlsm 的所有文件,用SCOPE='file:C:MyTestFolder' and replace CONTAINS(System.FileName, '""*.PDF""') 更改SCOPE='file:C:\look\here' 还不够` 与CONTAINS(System.FileName, ""Test*.xlsm""'),在sql 字符串中?当然,消除AND CONTAINS ('""find this text""')" 并以" 正确结束字符串。代码运行没有错误,但rs 以文件结尾...
        • 仅替换扩展名并使用 '""Test""' 的结果相同。而不是'""find this text""'。或'""Test*.xlsm""'
        • 该位置需要被搜索服务索引,试试文档之类的位置。
        • 我必须在使用任何命令之前添加:set cn = NEW ADODB.Connection set rs = NEW ADODB.Recordset,然后它可以完美运行。令人惊叹的脚本亚历克斯。非常感谢
        猜你喜欢
        • 2016-03-01
        • 2022-11-11
        • 2017-09-30
        • 2011-09-14
        • 2016-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多