It is quite common in applications to allow the user to specify a path and/or filename for saving files.
As such, a best practice would be to validate the user’s input prior to blindly using it and perhaps getting errors and crashing our applications.
Thus, I thought I’d quickly share one possible way to tackle this.
So the first thing to become aware of is that Microsoft Windows has rules that defined what isn’t allowed in file and path names. These rules are elaborated in:

but the highlights of the rules are:
a file name cannot include
- < > : ” / \ | ? *
- Ascii characters 0 through 31
furthermore, the name itself should not be one of the following reseerved words:
- CON,PRN,AUX,NUL,COM0,COM1,COM2,COM3,COM4,COM5,COM6,COM7,COM8,COM9,COM¹,COM²,COM³,LPT0,LPT1,LPT2,LPT3,LPT4,LPT5,LPT6,LPT7,LPT8,LPT9,LPT¹,LPT²,LPT³
there are a couple other things to avoid, but these are the most common aspects to respect.
Now, there are a variety of ways to approach this, we could:
- Use some file API and pass the name and if it errs we know it is invalid
- Build and use RegEx
- Use plain VBA to validate the string
Is The FileName Valid, Or Not? True or False
For today’s discussion, I chose the latter approach. As such, below is a sample function that will validate if the passed filename is acceptable based on the above rules.
'---------------------------------------------------------------------------------------
' Procedure : Filename_IsValid
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine is the proposed filename is valid or not based on Windows
' naming requirements
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: None required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFileName : Filename to validate (including extension)
'
' Usage:
' ~~~~~~
' ? Filename_IsValid("VBA Samples and Explanations.docx")
' Returns -> True
'
' ? Filename_IsValid("VBA Samples >>> Explanations.docx")
' Returns -> False
'
' ? Filename_IsValid("COM3.docx")
' Returns -> False
'
' Revision History:
' Rev Date(yyyy-mm-dd) Description
' **************************************************************************************
' 1 2024-03-25 Public Release
' 2 2024-03-28 Filename ending with '..' or ' '
'---------------------------------------------------------------------------------------
Public Function Filename_IsValid(sFilename As String) As Boolean
On Error GoTo Error_Handler
Dim iCounter As Long
Dim aChars() As String
Dim aNames() As String
Dim sFilenameWOExt As String 'Filename without extension
Dim IsValidFilename As Boolean
Const sIllegalChrs = "<,>,:,"",/,\,|,?,*"
Const sIllegalNames = "CON,PRN,AUX,NUL,COM0,COM1,COM2,COM3,COM4,COM5,COM6,COM7,COM8" & _
",COM9,COM¹,COM²,COM³,LPT0,LPT1,LPT2,LPT3,LPT4,LPT5,LPT6,LPT7" & _
",LPT8,LPT9,LPT¹,LPT²,LPT³"
'illegal characters
aChars = Split(sIllegalChrs, ",")
For iCounter = 0 To UBound(aChars)
If InStr(sFilename, aChars(iCounter)) > 0 Then
IsValidFilename = True
GoTo ReturnValue
End If
Next iCounter
'Ascii 0 through 31
For iCounter = 0 To 31
If InStr(sFilename, Chr(iCounter)) > 0 Then
IsValidFilename = True
GoTo ReturnValue
End If
Next iCounter
'Illegal names
If InStr(sFilename, ".") > 0 Then
sFilenameWOExt = Left(sFilename, InStrRev(sFilename, ".") - 1)
Else
sFilenameWOExt = sFilename 'No Extension
End If
aNames = Split(sIllegalNames, ",")
For iCounter = 0 To UBound(aNames)
If sFilenameWOExt = aNames(iCounter) Then
IsValidFilename = True
GoTo ReturnValue
End If
Next iCounter
'End with '..' or ' '
If Right(sFilename, 2) = ".." Or _
Right(sFilename, 2) = " " Then IsValidFilename = True
ReturnValue:
Filename_IsValid = Not IsValidFilename
Error_Handler_Exit:
On Error Resume Next
Exit Function
Error_Handler:
MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
"Error Source: Filename_IsValid" & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occurred!"
Resume Error_Handler_Exit
End Function
and there you have it a simple function that can validate if a string/filename is acceptable, or not.
Public Sub test()
Dim sFile As String
sFile = "SomeProposedFile*Name.xlsx"
If Filename_IsValid(sFile) Then
'All good, save as
Else
'The name is not acceptable, now what?! MsgBox
Debug.Print "Uh-oh"
End If
End Sub
and if we run this sub, we would then get output in the Immediate window:
Uh-oh
(because there is a * in the filename and that is one of the illegal characters)
Save a File
Another approach I have seen mentioned is to simply try and save the file with the given name and trap error that may arise. Here’s an example of one way it can be done:
'---------------------------------------------------------------------------------------
' Procedure : File_IsValidName
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine is the proposed path & filename is valid or not
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: None required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFile : Fully qualified path and filename to validate
'
' Usage:
' ~~~~~~
' File_IsValidName(Environ("Temp") & "\somefile.xlsx")
' Returns -> True
'
' File_IsValidName(Environ("Temp") & "\somefile>.xlsx")
' Returns -> False
'
' File_IsValidName(Environ("Temp") & "|\somefile.xlsx")
' Returns -> False
'
' Revision History:
' Rev Date(yyyy-mm-dd) Description
' **************************************************************************************
' 1 2024-03-25 Public release
'---------------------------------------------------------------------------------------
Function File_IsValidName(ByVal sFile As String) As Boolean
On Error GoTo Error_Handler
Dim iFileNumber As Integer
iFileNumber = FreeFile ' Get unused file number
Open sFile For Append As #iFileNumber ' Connect to the file
Close #iFileNumber ' Close the file
File_IsValidName = True
Kill sFile 'Remove the test file
Error_Handler_Exit:
On Error Resume Next
Exit Function
Error_Handler:
If Err.Number = 52 Then
'Bad file name or number
Else
MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
"Error Source: File_IsValidName" & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occurred!"
End If
Resume Error_Handler_Exit
End Function
I’m not a big fan of this approach as it is making useless I/O operations and we can properly validate things, as shown with the Filename_IsValid() function, with a little VBA and do everything in memory which is faster as well.
Basic ASCII Characters Only
Another great way to approach this is to simply limit the names of files and path to only use the basic ASCII characters: a-z, A-z, 0-9. This way you ensure no issues with special/invalid characters!
A RegEx Test is one way to approach to test this, refer to:
and taking things a little further we could build a function such as:
'---------------------------------------------------------------------------------------
' Procedure : RegEx_File_IsValidName
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine is the proposed path & filename is valid or not
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Late Binding -> none required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFile : Fully qualified path and filename to validate
'
' Usage:
' ~~~~~~
' RegEx_File_IsValidName(Environ("Temp") & "\somefile.xlsx")
' Returns -> True
'
' RegEx_File_IsValidName(Environ("Temp") & "\somefile>.xlsx")
' Returns -> False
'
' RegEx_File_IsValidName(Environ("Temp") & "|\somefile.xlsx")
' Returns -> False
'
' Revision History:
' Rev Date(yyyy-mm-dd) Description
' **************************************************************************************
' 1 2024-03-25 Public release
'---------------------------------------------------------------------------------------
Public Function RegEx_File_IsValidName(ByVal sFile As String) As Boolean
On Error GoTo Error_Handler
Dim oRegEx As Object
Set oRegEx = CreateObject("VBScript.RegExp")
oRegEx.Pattern = "^(?:[a-zA-Z]:(?:\\[^\\/:*?""<>|\r\n]+)*\\?|\\\\[^\\/:*?""<>|\r\n]+\\[^\\/:*?""<>|\r\n]+(?:\\[^\\/:*?""<>|\r\n]+)*\\?)$"
RegEx_File_IsValidName = oRegEx.test(sFile)
Error_Handler_Exit:
On Error Resume Next
If Not oRegEx Is Nothing Then Set oRegEx = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occured" & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: RegEx_File_IsValidName" & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
If you’re going this route, using RegEx, seriously consider using Self-Healing Object Variables!!!
More Information Please!
The above returns simply True/False, but in some case we want details so we might make the user aware of the exact issue so they may correct it and resubmit the name. As such, we could further customize the above function and get:
'---------------------------------------------------------------------------------------
' Procedure : Filename_IsValid2
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine is the proposed filename is valid or not based on Windows
' naming requirements
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: None required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFileName : Filename to validate (including extension)
' sProblem : Variable that returns the exact nature of the file name error
'
' Usage:
' ~~~~~~
' ? Filename_IsValid2("VBA Samples and Explanations.docx", sFileNameError)
' Returns -> True, sFileNameError -> ''
'
' ? Filename_IsValid2("VBA Samples >>> Explanations.docx", sFileNameError)
' Returns -> False, sFileNameError -> 'Invalid Characters '>''
'
' ? Filename_IsValid2("COM3.docx", sFileNameError)
' Returns -> False, sFileNameError -> 'Invalid Name 'COM3''
'
' Revision History:
' Rev Date(yyyy-mm-dd) Description
' **************************************************************************************
' 1 2024-03-25 Public Release
' 2 2024-03-28 Filename ending with '..' or ' '
'---------------------------------------------------------------------------------------
Public Function Filename_IsValid2(sFilename As String, _
ByRef sProblem As String) As Boolean
On Error GoTo Error_Handler
Dim iCounter As Long
Dim aChars() As String
Dim aNames() As String
Dim sFilenameWOExt As String 'Filename without extension
Dim IsValidFilename As Boolean
Const sIllegalChrs = "<,>,:,"",/,\,|,?,*"
Const sIllegalNames = "CON,PRN,AUX,NUL,COM0,COM1,COM2,COM3,COM4,COM5,COM6,COM7,COM8" & _
",COM9,COM¹,COM²,COM³,LPT0,LPT1,LPT2,LPT3,LPT4,LPT5,LPT6,LPT7" & _
",LPT8,LPT9,LPT¹,LPT²,LPT³"
'illegal characters
aChars = Split(sIllegalChrs, ",")
For iCounter = 0 To UBound(aChars)
If InStr(sFilename, aChars(iCounter)) > 0 Then
IsValidFilename = True
sProblem = "Invalid Characters '" & aChars(iCounter) & "'"
GoTo ReturnValue
End If
Next iCounter
'Ascii 0 through 31
For iCounter = 0 To 31
If InStr(sFilename, Chr(iCounter)) > 0 Then
IsValidFilename = True
sProblem = "Invalid ASCII Characters '" & iCounter & "'"
GoTo ReturnValue
End If
Next iCounter
'Illegal names
If InStr(sFilename, ".") > 0 Then
sFilenameWOExt = Left(sFilename, InStrRev(sFilename, ".") - 1)
Else
sFilenameWOExt = sFilename 'No Extension
End If
aNames = Split(sIllegalNames, ",")
For iCounter = 0 To UBound(aNames)
If sFilenameWOExt = aNames(iCounter) Then
IsValidFilename = True
sProblem = "Invalid Name '" & sFilenameWOExt & "'"
GoTo ReturnValue
End If
Next iCounter
'End with '..' or ' '
If Right(sFilename, 2) = ".." Then
IsValidFilename = True
sProblem = "Cannot end a file name with '..'"
GoTo ReturnValue
End If
If Right(sFilename, 2) = " " Then
IsValidFilename = True
sProblem = "Cannot end a file name with ' '"
GoTo ReturnValue
End If
ReturnValue:
Filename_IsValid2 = Not IsValidFilename
Error_Handler_Exit:
On Error Resume Next
Exit Function
Error_Handler:
MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
"Error Source: Filename_IsValid2" & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occurred!"
Resume Error_Handler_Exit
End Function
Public Sub test()
Dim sFile As String
Dim sFileNameError As String
sFile = "COM3.docx"
If Filename_IsValid2(sFile, sFileNameError) Then
'All good, save as
Debug.Print "'" & sFileNameError & "'"
Else
'The name is not acceptable, now what?! MsgBox
Debug.Print "'" & sFileNameError & "'"
End If
End Sub
and in the case of the above we would get an output in the immediate window of:
'Invalid Name 'COM3''
Naming Convention!
Perhaps the better approach, instead of letting users have complete free reign in naming files, would be to devise and code a File Naming Convention (FNC). This standardizes file names, makes them easier to easily decipher, simplifies sorting and can avoid the entire issue of having potentially invalid file names.
Typically, in a FNC we might see:
- Date
- Category/Subject
- Name
- Revision
20240313_Engineering_RFC_V12RevA.docx
The objective should be to provide a name that provide as much information as possible in the shortest name possible. You should not build filename that take 100-150+ characters.
Even Harvard recommends it:
Such a format could then easily be incorporated into a form with various choices made by the users and the filename automatically generated based on those choices.
In my career, I’ve also been exposed to alphanumeric naming conventions, things like:
095ATP45_2.1.doc
where the name itself can be broken down into components like:
- 095 -> HR
- ATP -> New Employee User Manual
- 45 -> James Carleson
- 2.1 -> Revision Number
This is not a great approach as it requires one to always have the corporate naming convention to decipher what the document actually is! Things should be easily understood by simply looking at the name!!
