VBA中的DIR(路径)是否有办法处理超过260的字符串?

时间:2013-02-06 02:40:38

标签: excel vba excel-vba

给出以下代码段:

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中运行它

5 个答案:

答案 0 :(得分: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个字符。本地人   path按以下顺序构成:驱动器号,冒号,   反斜杠,名称由反斜杠分隔的组件和终止   空字符。例如,驱动器D上的最大路径是“D:\ some   256个字符的路径字符串“where”“表示不可见的   终止当前系统代码页的空字符。 (该   字符< >这里使用的是视觉清晰度,不能成为其中的一部分   有效的路径字符串。)注意Windows API中的文件I / O函数   将“/”转换为“\”作为将名称转换为NT样式名称的一部分,   除了使用“\?\”前缀时,如下所述   部分。 Windows API具有许多也具有Unicode的功能   版本允许最大总路径的扩展长度路径   长度为32,767个字符。这种类型的路径由   由反斜杠分隔的组件,每个组件都返回到返回的值   GetVolumeInformation的lpMaximumComponentLength参数   function(此值通常为255个字符)。指定一个   扩展长度路径,使用“\?\”前缀。例如,“\?\ D:\ very   长路径“。注意最大路径为32,767个字符   近似,因为“\?\”前缀可能会扩展到更长   系统在运行时的字符串,这个扩展适用于   总长度。

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

  

对于文件I / O,路径字符串的“\?\”前缀告诉Windows   用于禁用所有字符串解析并发送后续字符串的API   它直接到文件系统。例如,如果是文件系统   支持大路径和文件名,可以超过MAX_PATH   Windows API强制执行的限制。更多   有关正常最大路径限制的信息,请参阅前面的内容   部分最大路径长度限制。

必须有DECLARE并且可以使用的Win32 API函数,但是没有使用DIR函数。对不起,手边没有长路径来测试任何东西...

答案 1 :(得分: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

答案 2 :(得分: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

答案 3 :(得分:0)

我找到了这个MS页面: Naming Files, Paths, and Namespaces

  

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

     

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

     

" \?\"前缀也可以与根据通用命名约定(UNC)构造的路径一起使用。要使用UNC指定此类路径,请使用" \?\ UNC \"字首。例如," \?\ UNC \ server \ share",其中" server"是计算机的名称和"分享"是共享文件夹的名称。这些前缀不会用作路径本身的一部分。它们表明路径应该以最小的修改传递给系统,这意味着您不能使用正斜杠表示路径分隔符,或者表示当前目录的句点,或者表示父目录的双点。因为你不能使用" \?\"带有相对路径的前缀,相对路径总是限制为总共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)

答案 4 :(得分:0)

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

您需要一个调用system32的函数来建立到网络驱动器的直接路径。我从here

获得了代码

这里是代码,将私有函数插入模块顶部,否则将无法正常工作。如果您想将其打开到整个工作簿,则可以将功能保持与该模块的专用联系。

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

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

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