9

给定以下代码段:

Dim s As String: s = "S:\vic\bla\[..insert more here..]\data.xml"
Debug.Print Len(s)
Debug.Print Dir(s)

如果Len(s) >= 260我收到说明以下内容的错误:

Run-time error '53':

File not found

如果字符串小于 260,它可以正常工作并显示已找到和未找到文件的预期行为。

是否可以让 DIR 使用长(> 260)路径名?

笔记

  • 文件重组不是一种选择

  • 我在 Excel 2007 中运行它

4

5 回答 5

6

简而言之(回答标题的答案):不。VBA 的Dir功能根本不适用于超过 260 个字符的路径。

长版: http: //msdn.microsoft.com/en-us/library/aa365247 (VS.85).aspx#maximum_path_length (然后 Ctrl+F 并搜索“260”)

最大路径长度限制

在 Windows API(以下段落中讨论的一些例外情况)中,路径的最大长度为 MAX_PATH,定义为 260 个字符。本地路径按以下顺序构造:驱动器号、冒号、反斜杠、由反斜杠分隔的名称组件和终止空字符。例如,驱动器 D 上的最大路径是“D:\some 256-character path string”,其中“”表示当前系统代码页的不可见终止空字符。(字符 < > 在此处用于视觉清晰,不能作为有效路径字符串的一部分。) 注意 Windows API 中的文件 I/O 函数将“/”转换为“\”作为将名称转换为 NT-样式名称,除非使用以下部分中详述的“\?\”前缀。Windows API 有许多函数也有 Unicode 版本,以允许最大总路径长度为 32,767 个字符的扩展长度路径。这种类型的路径由由反斜杠分隔的组件组成,每个组件都达到 GetVolumeInformation 函数的 lpMaximumComponentLength 参数中返回的值(该值通常为 255 个字符)。要指定扩展长度的路径,请使用“\?\”前缀。例如,“\?\D:\非常长的路径”。注意 最大路径 32,767 个字符是近似值,因为“\?\”前缀可能会在运行时被系统扩展为更长的字符串,并且此扩展适用于总长度。767 个字符。这种类型的路径由由反斜杠分隔的组件组成,每个组件都达到 GetVolumeInformation 函数的 lpMaximumComponentLength 参数中返回的值(该值通常为 255 个字符)。要指定扩展长度的路径,请使用“\?\”前缀。例如,“\?\D:\非常长的路径”。注意 最大路径 32,767 个字符是近似值,因为“\?\”前缀可能会在运行时被系统扩展为更长的字符串,并且此扩展适用于总长度。767 个字符。这种类型的路径由用反斜杠分隔的组件组成,每个组件的最大长度为 GetVolumeInformation 函数的 lpMaximumComponentLength 参数中返回的值(该值通常为 255 个字符)。要指定扩展长度的路径,请使用“\?\”前缀。例如,“\?\D:\非常长的路径”。注意 最大路径 32,767 个字符是近似值,因为系统在运行时可能会将“\?\”前缀扩展为更长的字符串,并且此扩展适用于总长度。

我认为关于Win32 File NameSpaces的部分值得一试:

对于文件 I/O,路径字符串的“\?\”前缀告诉 Windows API 禁用所有字符串解析并将紧随其后的字符串直接发送到文件系统。例如,如果文件系统支持大路径和文件名,则您可以超过由 Windows API 强制执行的 MAX_PATH 限制。有关正常最大路径限制的更多信息,请参阅上一节最大路径长度限制。

必须有一个 Win32 API 函数您可以DECLARE使用,但这不是使用该DIR函数。抱歉,手头没有长路径名来测试任何东西......

于 2013-02-06T04:12:46.410 回答
3

这是一些无论深度如何都应该工作的代码......基本上,它指定了相对路径 - 所以你永远不会dir用长字符串调用

Function deepFileExists(longFileName As String)
' slowly make your way to the deepest folder...
' assuming "\" is used as separator
' you could add some code to replace "/" with "\"...

Dim pathFragment As String, currentDir As String
Dim slash As Integer, lastSlash As Integer

slash = InStr(1, longFileName, "\")
lastSlash = 0

pathFragment = Mid(longFileName, 1, slash - 1)

currentDir = CurDir        ' save the current directory
ChDrive pathFragment       ' making sure we have the right drive
ChDir pathFragment & "\"   ' be at the root of this drive's directory

lastSlash = slash
slash = InStr(slash + 1, longFileName, "\")

While (slash > 0)
  pathFragment = ".\" & Mid(longFileName, lastSlash + 1, slash - lastSlash)
  ChDir pathFragment
  'MsgBox "changing directory to " & pathFragment
  lastSlash = slash
  slash = InStr(slash + 1, longFileName, "\")
Wend

' now we can look for the file:
Dim a
a = Dir(Mid(longFileName, lastSlash + 1))
If Len(a) > 0 Then
  deepFileExists = True
Else
  deepFileExists = False
End If

End Function
于 2013-02-06T14:34:31.183 回答
2

我无法对此进行测试,因此您所拥有的只是一些关于可能方法的粗略说明。

''Reference: Windows Script Host Object Model
Dim fs As New FileSystemObject
Dim fl As Folder
Dim fl2 As Folder

Set fl = fs.GetFolder("Z:\Docs\test\ThisIsInOrderToCreate\ALongFilePath\")
Set fl2 = fl.SubFolders("WithASubFolder")
Debug.Print fl2.ShortPath
For Each File In fl2.Files
    If File.Name = "file.txt" Then
        Debug.Print "Found"
    End If
Next

''May be possible
a = Dir(fl.ShortPath & "\file.*")

另外,关于上面的评论:

Set WshNetwork = CreateObject("WScript.Network")
WshNetwork.MapNetworkDrive "L:", "\\mydrive\share"
''Important to destroy when you are finished
Set WshNetwork = Nothing
于 2013-02-06T12:58:32.343 回答
0

我找到了这个 MS 页面: 命名文件、路径和命名空间

最大路径长度限制 在 Windows API(以下段落中讨论的一些例外情况)中,路径的最大长度为 MAX_PATH,定义为 260 个字符。本地路径按以下顺序构造:驱动器号、冒号、反斜杠、由反斜杠分隔的名称组件和终止空字符。例如,驱动器 D 上的最大路径是“D:\some 256-character path string”,其中“”表示当前系统代码页的不可见终止空字符。(字符 < > 在这里用于视觉清晰,不能作为有效路径字符串的一部分。) 注意 Windows API 中的文件 I/O 函数将“/”转换为“\”作为将名称转换为 NT-样式名称,除非使用“\?\”

Windows API 有许多函数也有 Unicode 版本,以允许最大总路径长度为 32,767 个字符的扩展长度路径。这种类型的路径由由反斜杠分隔的组件组成,每个组件都达到 GetVolumeInformation 函数的 lpMaximumComponentLength 参数中返回的值(该值通常为 255 个字符)。要指定扩展长度的路径,请使用“\?\”前缀。例如,“\?\D:\非常长的路径”。注意 最大路径 32,767 个字符是近似值,因为“\?\”前缀可能会在运行时被系统扩展为更长的字符串,并且此扩展适用于总长度。

“\?\”前缀也可以用于根据通用命名约定 (UNC) 构建的路径。要使用 UNC 指定此类路径,请使用“\?\UNC\”前缀。例如,“\?\UNC\server\share”,其中“server”是计算机的名称,“share”是共享文件夹的名称。这些前缀不用作路径本身的一部分。它们表明路径应该以最少的修改传递给系统,这意味着您不能使用正斜杠来表示路径分隔符,或者使用句点来表示当前目录,或者使用双点来表示父目录。因为您不能将“\?\”前缀与相对路径一起使用,所以相对路径总是限制为总共 MAX_PATH 字符。

因此,对于很长的 UNC 路径,我更改了路径的开头,如下所示,它可以工作。

   Const MAX_PATH_LENGTH As Integer = 260

    If Len(fname) > MAX_PATH_LENGTH Then
        fname = "\\?\UNC\" & Mid$(fname, 3)
    End If
    Set fsoObject = New Scripting.FileSystemObject
    FileExists = fsoObject.FileExists(fname)
于 2017-10-09T12:57:19.287 回答
0

由于我无法回复包含 deepfileexists 代码的评论,因此这里修改了代码,以便您可以找到网络路径(因为他回答说他有网络位置)

您需要一个调用 system32 的函数来执行到网络驱动器的直接路径。我从这里得到了代码

继承人代码,在模块顶部插入私有函数,否则它将不起作用。它使功能专门与该模块相关联,如果您想将其打开到整个工作簿,请关闭私有功能。

Private Declare Function SetCurrentDirectoryA Lib "kernel32" _
    (ByVal lpPathName As String) As Long

然后是带有修改后代码的函数,以在网络驱动器以 \ 开头时接受该函数

Function deepFileExists(longFileName As String)
' slowly make your way to the deepest folder...
' assuming "\" is used as separator
' you could add some code to replace "/" with "\"...


Dim pathFragment As String, currentDir As String
Dim slash As Integer, lastSlash As Integer

If Left(longFileName, 2) = "\\" Then
    slash = InStr(3, longFileName, "\")
    Else
    slash = InStr(1, longFileName, "\")
End If

lastSlash = 0

pathFragment = Mid(longFileName, 1, slash - 1)

currentDir = CurDir        ' save the current directory
If Not Left(pathFragment, 2) = "\\" Then
    ChDrive pathFragment       ' making sure we have the right drive
    ChDir pathFragment & "\"   ' be at the root of this drive's directory
    Else
        SetCurrentDirectoryA (pathFragment)
End If

lastSlash = slash
slash = InStr(slash + 1, longFileName, "\")

While (slash > 0)
    pathFragment = ".\" & Mid(longFileName, lastSlash + 1, slash - lastSlash)
    If Not Left(longFileName, 2) = "\\" Then
        ChDir pathFragment
    Else
        SetCurrentDirectoryA (pathFragment)
    End If
    'MsgBox "changing directory to " & pathFragment
    lastSlash = slash
    slash = InStr(slash + 1, longFileName, "\")
Wend

' now we can look for the file:
Dim a As String
Dim something As String
something = Mid(longFileName, lastSlash + 1)

a = Dir(something)
If Len(a) > 0 Then
    deepFileExists = True
Else
    deepFileExists = False
End If

End Function
于 2018-10-18T11:56:42.940 回答