vbscriptapi-designfilesystemobject

Why doesn't FileExists support wildcards?


Consider this example VBScript fragment:

Dim fs
Set fs = CreateObject("Scripting.FileSystemObject")
If fs.FileExists("D:\Folder\File*.ext") Then ' Finds nothing!
  fs.CopyFile "D:\Folder\File*.ext", "D:\OtherFolder\"
  fs.Deletefile "D:\Folder\File*.ext"
End If

The FileExists method turns out not to support wildcards (* and ?). Not does FolderExists. I expected wildards to just work because they work fine for all similar methods in the FileSystemObject: CopyFile, CopyFolder, MoveFile, MoveFolder, DeleteFile, DeleteFolder and the Get* filename handling methods like GetAbsolutePathName.

Of course there are ways to work around this, like GetFolder and iterating over its files. But FileExists would have been much more readable, convenient, natural and consistent.

The fs.FileExists inconsistency feels like an API design problem. What could be the reason? Is there some idea behind it?


Solution

  • Only someone from the team that designed the Microsoft Scripting Runtime API (scrrun.dll), which these functions are a part of, can answer this question for sure.

    But my guess is that FileExists is nothing but a wrapper for the CreateFile Windows API function with the dwCreationDisposition parameter set to OPEN_EXISTING ("Opens a file or device only if it exists."). This Windows API function does not support wildcards, so FileExists can't, either.

    When the file does not exist, the system will respond with error 2 ("The system cannot find the file specified.") and FileExists will return False.

    The above is based on using Process Monitor to inspect the behavior of a FileExists call.

    It would be moot to discuss whether this is an API design oversight and whether it should be any different.


    That being said, there is no reason for an "exists" check in the code you show.

    If you want to move files from location A to location B, just do that.

    If there is something to move, it will be moved. If there is nothing to move, there will be an error you can inspect. The "exists" check provides no extra information whatsoever.

    Dim fs, source
    Set fs = CreateObject("Scripting.FileSystemObject")
    
    On Error Resume Next
    
    fs.MoveFile "File*.ext", "D:\OtherFolder\"
    
    If Err.Number = 0 Then
      MsgBox "Done"
    ElseIf Err.Number = 53 Then ' File not found
      MsgBox "Nothing to do"
    ElseIf Err.Number = 76 Then ' Path not found
      MsgBox "Target path not found"
    Else
      MsgBox "Unexpected Error " & Err.Number & " - " & Err.Description
    End If
    
    On Error Goto 0
    

    For convenience I would wrap that in a Sub so that I can re-use it and the On Error Resume Next won't leak into the rest of my code.

    It's also worth noting that within the same volume, MoveFile will be way faster than copy-and-delete.