访问具有长路径(超过 260)的文件

Access files with long paths (over 260)

我正在使用 Microsoft Scripting Runtime (FSO) 来解析文件夹并生成其所有内容的列表,这些文件夹在网络上,结果路径最终超过 260。我拥有的最少代码如下以下:-

Private Sub ProcessFolder(ByVal StrFolder As String)
Dim Fl              As File
Dim Fldr            As Folder
Dim RootFldr        As Folder

Set RootFldr = FS.GetFolder(StrFolder)

    For Each Fl In RootFldr.Files
        Debug.Print Fl.Path
    Next

    For Each Fldr In RootFldr.SubFolders
        DoEvents
        ProcessFolder Fldr.Path
    Next

Set RootFldr = nothing    
End sub

在某个级别StrFolder长度变为259,Set RootFldr ...文件夹行有效但For Each Fl In RootFldr.Files给出了76: Path not found的错误,大概是因为内容导致了路径突破 260 限制。

在 Windows 资源管理器中查找时文件夹中有文件。当我将结果输出到工作簿时,我使用 Excel 作为此代码的宿主。

为了非常清楚地说明我的问题及其背景,我需要使用 FSO(如果存在替代方案,我很乐意展示)来访问其网络路径中深度超过 260 个字符的文件。我需要它作为 FSO,因为我拥有的工具正在获取文件夹路径和文件路径、名称、创建和修改的大小。

将 MAXFILE 阻碍的 DOS 路径名转换为本机 OS 路径名的技术已经很成熟 and documented。总结:

  • 使用 \?\ 驱动器号的路径前缀,例如 \?\C:\foo\bar\baz.txt
  • 为使用文件共享的路径添加 '\?\UNC\ 前缀,例如 \?\UNC\server\share\baz.txt.

与 FileSystemObject 一起工作也很好,至少当我在 Windows 10 上测试您的代码时是这样。在较旧的 Windows 版本或您服务器上的网络重定向器中可能不一定如此。通过使用 FAR 文件管理器创建具有长名称的子目录进行测试,并通过以下方式验证:

Dim path = "\?\C:\temp\LongNameTest"
ProcessFolder path

出品:

\?\c:\temp\LongNameTest\VeryLongFolderName0123456789012345678901234567890123456789012345678901234567890123456789\VeryLongFolderName0123456789012345678901234567890123456789012345678901234567890123456789\VeryLongFolderName0123456789012345678901234567890123456789012345678901234567890123456789\VeryLongFolderName0123456789012345678901234567890123456789012345678901234567890123456789\VeryLongFolderName0123456789012345678901234567890123456789012345678901234567890123456789\Chrysanthemum.jpg

长度为 488 个字符。注意事项:

  • 本机路径名必须是完整路径,不能是相对路径。换句话说,它们必须始终以驱动器号或共享名开头,并从 drive/share.
  • 的根目录开始
  • 你得到了本地路径名,如果你显示它,不要忘记再次去掉前缀。
  • 未测试但应该会失败,文件名本身(不包括目录名)的长度仍有限制,不能超过 259 个字符。应该不是问题,因为用户也不能创建它们。

这需要一点创意编码,但使用 ShortPath 就是答案。

此工具用于创建根文件夹中每个文件夹和文件的列表,文件还显示它们的大小和 created/modified 日期。问题是当文件或文件夹的结果路径超过 260 时,会抛出错误 Error 76: Path Not Found,并且代码不会捕获该区域的内容。

使用 Microsoft Scripting Runtime (FSO) ShortPath 可以解决这个问题,但路径从人类可读到编码:-

完整路径 \ServerName00000\Root_Root_contentmanagement\DPT\STANDARDS_GUIDELINES\VENDOR_CERTIFICATION_FILES\PDFX_CERTIFICATION_ALL06_2007\DPT\CompantName0\Approved\Quark\India under Colonial Rule_structure sample8231738X\Douglas M. Peers_01_058231738X\SUPPORT\ADDITIONAL INFORMATION\IUC-XTG & XML file

短路径 \lo3uppesaapp001\pesa_cmcoe_contentmanagement\CTS\S4SJ05~5\V275SE~8\PDM5D9~GN52EQ~5\HPE\GS9C6L~U\Approved\Quark\IQPSJ5~F[=15=]CWHH1~G\DOFNHA~8\SUPPORT\A6NO7S~K\IUC-XTG & XML file

(注意我已经更改了保护 IP 和公司信息的完整路径,但大小相同)

你可以看到虽然我可以将短路径传递给某人并且他们可以将它放入 Windows Explorer 中以到达那里,但他们只需看一下就知道它去了哪里,绕过这个用过的将文件夹路径保持为完整字符串并遵循短路径的全局变量。这个字符串就是我输出给用户的。下面的代码被删减了,但显示了我是如何实现的。

简短的回答是 ShortPath 在 FSO 中会解决这个问题,但路径不会很好。

Dim FS              As New FileSystemObject
Dim LngRow          As Long
Dim StrFolderPath   As String
Dim WkBk            As Excel.Workbook
Dim WkSht           As Excel.Worksheet

Public Sub Run_Master()

Set WkBk = Application.Workbooks.Add

    WkBk.SaveAs ThisWorkbook.Path & "\Data.xlsx"

    Set WkSht = WkBk.Worksheets(1)

        WkSht.Range("A1") = "Path"
        WkSht.Range("B1") = "File Name"
        WkSht.Range("C1") = "Size (KB)"
        WkSht.Range("D1") = "Created"
        WkSht.Range("E1") = "Modified"

        LngRow = 2

        Run "\ServerName00000\AREA_DEPT0_TASK000"

    Set WkSht = Nothing

    WkBk.Close 1
Set WkBk = Nothing

MsgBox "Done!"

End Sub

Private Sub Run(ByVal StrVolumeToCheck As String)
Dim Fldr            As Folder
Dim Fldr2           As Folder

Set Fldr = FS.GetFolder(StrVolumeToCheck)

    'This is the variable that follows the full path name
    StrFolderPath = Fldr.Path

    WkSht.Range("A" & LngRow) = StrFolderPath
    LngRow = LngRow +1

    For Each Fldr2 In Fldr.SubFolders
        If (Left(Fldr2.Name, 1) <> ".") And (UCase(Trim(Fldr2.Name)) <> "LOST+FOUND") Then
            ProcessFolder Fldr2.Path
        End If
    Next

Set Fldr = Nothing

End Sub

Private Sub ProcessFolder(ByVal StrFolder As String)
'This is the one that will will be called recursively to list all files and folders
Dim Fls             As Files
Dim Fl              As File
Dim Fldrs           As Folders
Dim Fldr            As Folder
Dim RootFldr        As Folder

Set RootFldr = FS.GetFolder(StrFolder)

    If (RootFldr.Name <> "lost+found") And (Left(RootFldr.Name, 1) <> ".") Then

        'Add to my full folder path
        StrFolderPath = StrFolderPath & "\" & RootFldr.Name

        WkSht.Range("A" & LngRow) = StrFolderPath
        WkSht.Range("D1") = RootFldr.DateCreated
        WkSht.Range("E1") = RootFldr.DateLastModified
        Lngrow = LngRow + 1

        'This uses the short path to get the files in FSO
        Set Fls = FS.GetFolder(RootFldr.ShortPath).Files

            For Each Fl In Fls
                'This output our string variable of the path (i.e. not the short path)
                WkSht.Range("A" & LngRow) = StrFolderPath
                WkSht.Range("B" & LngRow) = Fl.Name
                WkSht.Range("C" & LngRow) = Fl.Size /1024 '(bytes to kilobytes)
                WkSht.Range("D" & LngRow) = Fl.DateCreated
                WkSht.Range("E" & LngRow) = Fl.DateLastModified

                LngRow = LngRow + 1

            Next
        Set Fls = Nothing

        'This uses the short path to get the sub-folders in FSO
        Set Fldrs = FS.GetFolder(RootFldr.ShortPath).SubFolders
            For Each Fldr In Fldrs
                'Recurse this Proc
                ProcessFolder Fldr.Path
                DoEvents
            Next
        Set Fldrs = Nothing

        'Now we have processed this folder, trim the folder name off of the string
        StrFolderPath = Left(StrFolderPath, Len(StrFolderPath) - Len(RootFldr.Name)+1)

    End If
Set RootFldr = Nothing

End Sub

如前所述,这是我正在使用的代码的删减版本,用于举例说明用于超越此限制的方法。一旦我完成它,实际上看起来很简陋。

我使用命令 shell 的 subst 命令解决了这个问题。它允许您将驱动器号分配给本地路径(有点像网络共享)。