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 には、最大合計パス長 32,767 文字の拡張長パスを許可する Unicode バージョンもある多くの関数があります。このタイプのパスは、バックスラッシュで区切られたコンポーネントで構成され、それぞれが 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

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 に答える