Home > Software design >  Check file existence in VBA for files with long path
Check file existence in VBA for files with long path

Time:11-08

Windows has a 256 characters limit for file paths, but users can definitely create files with path longer than 256 characters. Let's call file paths shorter than or equal 255 characters as short paths, and those longer than or equal to 256 characters as long path.

While working on another problem, I need to check whether a file exists given its file path, regardless of the length of the file path, regardless of normal paths or UNC paths on Windows. Is it possible with VBA?


What I have tried

In VBA, there are two main ways to check file existence:

  1. Use Dir().
Dim isExists As Boolean
isExists = Dir("some\file\path") = vbNullString
  1. Use FileSystemObject (FSO).
Dim objFSO As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")

Dim isExists As Boolean
isExists = objFSO.FileExists("some\file\path")

Dir() is not useful here because:

  • It does not support file paths with Unicode characters, e.g. Chinese characters. And there are Chinese characters in the file paths that I work with.
  • For long paths, it throws File Not Found error no matter the file exists or not.

FileSystemObject, on the other hand, supports file paths with Unicode characters, but I cannot get it to report file existence correctly for files with a long path.

Whenever a long path is given, objFSO.FileExists(...) returns False even when the file obviously exists in Windows File Explorer?!

For example,

' Short paths: `True` if file exists and `False` otherwise, as expected.
objFSO.FileExists("C:\some\short\path")  ' Windows native path.
objFSO.FileExists("\\server\drive\some\short\path")  ' UNC path.

' Long paths: `False` no matter the file exists or not, unfortunately.
objFSO.FileExists("C:\some\very\long\path\that\may\have\unicode\characters")  ' Windows native path.
objFSO.FileExists("\\server\drive\some\very\long\path\that\may\have\unicode\characters")  ' UNC path.

I have read the Microsoft VBA documentation many times, e.g. FileExists method, but with no luck.

Please forgive me to insert a small rant here that nowhere in the documentation of Dir() mentions the fact that it does not support Unicode characters. Come on!


What I expect

Can anyone please point out what I may have missed, or answer the question whether this is solvable with VBA? If so, what can I do? It will be kind of you if you include some code examples to illustrate your answer. Thank you!

CodePudding user response:

The Naming Files, Paths, and Namespaces page states the following:

In the Windows API (with some exceptions discussed in the following paragraphs), the maximum length for a path is MAX_PATH, which is defined as 260 characters.

The Windows API has many functions that also have Unicode versions to permit an extended-length path for a maximum total path length of 32,767 characters. This type of path is composed of components separated by backslashes, each up to the value returned in the lpMaximumComponentLength parameter of the GetVolumeInformation function (this value is commonly 255 characters). To specify an extended-length path, use the "\?" prefix. For example, "\?\D:\very long path".

Because you cannot use the "\?" prefix with a relative path, relative paths are always limited to a total of MAX_PATH characters.

You may try using Windows API functions, for example, you can use following function:

[DllImport("shlwapi", EntryPoint = "PathFileExists", CharSet = CharSet.Unicode)]
public static extern bool PathExists(string path);

Read more about possible workarounds in the following threads:

CodePudding user response:

After more research, I have come up with a workable VBA function to do what I want.

Please feel free to comment if there is anything that can be improved.

Function IsFileExists

Function IsFileExists(filepath As String) As Boolean
' Determine whether a file exists given its (absolute) file path, regardless
' of path length.
'
' filepath:
'     The (absolute) file path to be checked for file existence. Can be 
'     native paths or UNC paths, short or long, extended with "\\?\" or 
'     "\\?\UNC" or not.
' Return: True if the file exists, False otherwise.

    Dim objFSO As Object
    Set objFSO = CreateObject("Scripting.FileSystemObject")

    ' FileSystemObject is sufficient for short paths.
    If Len(filepath) <= 255 Then
        IsFileExists = objFSO.FileExists(filepath)
        Exit Function
    End If

    ' Long paths.
    If Left(filepath, 4) = "\\?\" Then
        ' Example: \\?\UNC\Server\Share\Some\Very\Long\Path
        ' Example: \\?\C:\Some\Very\Long\Path
        ' No action.
    ElseIf Left(filepath, 2) = "\\" Then
        ' Example: \\Server\Share\Some\Very\Long\Path
        filepath = objFSO.BuildPath("\\?\UNC\", Mid(filepath, 2))
    Else
        ' Example: C:\Some\Very\Long\Path
        filepath = objFSO.BuildPath("\\?\", filepath)
    End If

    IsFileExists = objFSO.FileExists(filepath)
End Function

Brief Explanation

As mentioned in Eugene's prompt answer (Thanks a lot to him), Windows API limits the length of file paths to 260 characters, but it is possible to have extended file paths by prefixing the paths with \\?\ or \\?\UNC\.

My function above distinguishes short paths and long paths, and extend the paths when needed, and then uses FileSystemObject to check file existence.

One caveat of the function is that \\?\ cannot be used on relative paths, but I wrote this function with absolute paths in mind only. Long relative paths may need to be converted to absolute paths before inputting to this function.

Other method(s)

PathFileExistsW in shlwapi

As of writing, I cannot successfully make PathFileExistsW in shlwapi to work using Declare Function in VBA. And I am a bit skeptical about it because Microsoft documentation says the said function's only parameter accepts "[a] pointer to a null-terminated string of maximum length MAX_PATH that contains the full path of the object to verify." (emphasis mine). I shall update when I can make it work to test it.

Reference

  • Related