Chad
Chad

Reputation: 24689

Valid filename check. What is the best way?

See subject of positing for question.

1) I recall seeing a really cool option in VB.NET using LINQ to match using "LIKE%'

2) I know regular expressions will work and I suspect that will result in the shortest code and probably won't be too hard to read for such a simple test.

Here's what I did. Warning: You're gonna hate it.

Private Shared Function FileNameIsOk(ByVal fileName As String) As Boolean

    For Position As Integer = 0 To fileName.Length - 1

        Dim Character As String = fileName.Substring(Position, 1).ToUpper
        Dim AsciiCharacter As Integer = Asc(Character)

        Select Case True

            Case Character = "_" 'allow _
            Case Character = "." 'allow .
            Case AsciiCharacter >= Asc("A") And AsciiCharacter <= Asc("A") 'Allow alphas
            Case AsciiCharacter >= Asc("0") AndAlso AsciiCharacter <= Asc("9") 'allow digits

            Case Else 'otherwise, invalid character
                Return False

        End Select

    Next

    Return True

End Function

Upvotes: 13

Views: 38863

Answers (12)

user3190427
user3190427

Reputation: 1

Try this

Function IsValidFileNameOrPath(ByVal name As String) As Boolean

    Dim i As Integer
    Dim dn, fn As String

    i = InStrRev(name, "\") : dn = Mid(name, 1, i) : fn = Mid(name, i + 1)
    MsgBox("directory = " & dn & " : file = " & fn)

    If name Is Nothing Or Trim(fn) = "" Then
        MsgBox("null filename" & fn)
        Return False
    Else
        For Each badchar As Char In Path.GetInvalidFileNameChars
            If InStr(fn, badchar) > 0 Then
                MsgBox("invalid filename" & fn)
                Return False
            End If
        Next
    End If

    If dn <> "" Then
        If InStr(dn, "\\") > 0 Then
            MsgBox("duplicate \ =  " & dn)
            Return False
        End If
        For Each badChar As Char In Path.GetInvalidPathChars
            If InStr(dn, badChar) > 0 Then
                MsgBox("invalid directory=  " & dn)
                Return False
            End If
        Next
        If Not System.IO.Directory.Exists(dn) Then
            Try
                Directory.CreateDirectory(dn)
                'Directory.Delete(dn)
            Catch
                MsgBox("invalid path =  " & dn)
                Return False
            End Try
        End If
    End If
    Return True
End Function

Upvotes: 0

codiee
codiee

Reputation: 31

This is a easy way works, even on folders:

    Try
        My.Computer.FileSystem.WriteAllText("aux", "Hello World!", False)
    Catch ex As Exception
        'do nothing or inform the user
    End Try

Upvotes: -1

Joel Coehoorn
Joel Coehoorn

Reputation: 415765

Old now, but I saw this and just had to add a new answer. The current accepted and other answers are way more complicated than needed. In fact, it can be reduced to a single line:

Public Shared Function FilenameIsOK(ByVal fileName as String) as Boolean
    Return Not (Path.GetFileName(fileName).Intersect(Path.GetInvalidFileNameChars()).Any() OrElse Path.GetDirectoryName(fileName).Intersect(Path.GetInvalidPathChars()).Any()) 
End Function

Though I wouldn't recommend writing it that way. Break it up just a little bit to improve readability:

Public Shared Function FilenameIsOK(ByVal fileName as String) as Boolean
    Dim file As String = Path.GetFileName(fileName)
    Dim directory As String = Path.GetDirectoryName(fileName)

    Return Not (file.Intersect(Path.GetInvalidFileNameChars()).Any() _
                OrElse _ 
                directory.Intersect(Path.GetInvalidPathChars()).Any()) 
End Function

One other point here, is often the best way to deal with file system issues is to let the file system tell you: try to open or create the file in question, and deal with the exception. This works especially well, because you'll likely have to do this anyway. Any other validation you do here is duplicated effort for work you'll still have to put into an exception handler.

Upvotes: 16

elparadise
elparadise

Reputation: 1

Public Function IsValidFileName(nFile As String) As Boolean
    Try
        Dim S As String = Path.GetFileName(nFile)
    Catch
        Return False
    End Try
    Return True
End Function

Upvotes: 0

Kon
Kon

Reputation: 21

I cannot take credit for this one (well two) liner. I found it whilst googling-cant remember where I found it.

    Dim newFileName As String = "*Not<A>Good:Name|For/\File?"
    newFileName = String.Join("-", fileName.Split(IO.Path.GetInvalidFileNameChars))

Upvotes: 2

DrMarbuse
DrMarbuse

Reputation: 870

Based on Joel Coehoorns well written solution, I added some additional functionality for validation.

    ''' <summary>
    ''' Check if fileName is OK
    ''' </summary>
    ''' <param name="fileName">FileName</param>
    ''' <param name="allowPathDefinition">(optional) set true to allow path definitions. If set to false only filenames are allowed</param>
    ''' <param name="firstCharIndex">(optional) return the index of first invalid character</param>
    ''' <returns>true if filename is valid</returns>
    ''' <remarks>
    ''' based on Joel Coehoorn answer in 
    ''' http://stackoverflow.com/questions/1014242/valid-filename-check-what-is-the-best-way
    ''' </remarks>
    Public Shared Function FilenameIsOK(ByVal fileName As String, _
                                        Optional ByVal allowPathDefinition As Boolean = False, _
                                        Optional ByRef firstCharIndex As Integer = Nothing) As Boolean

        Dim file As String = String.Empty
        Dim directory As String = String.Empty

        If allowPathDefinition Then
            file = Path.GetFileName(fileName)
            directory = Path.GetDirectoryName(fileName)
        Else
            file = fileName
        End If

        If Not IsNothing(firstCharIndex) Then
            Dim f As IEnumerable(Of Char)
            f = file.Intersect(Path.GetInvalidFileNameChars())
            If f.Any Then
                firstCharIndex = Len(directory) + file.IndexOf(f.First)
                Return False
            End If

            f = directory.Intersect(Path.GetInvalidPathChars())
            If f.Any Then
                firstCharIndex = directory.IndexOf(f.First)
                Return False
            Else
                Return True
            End If
        Else
            Return Not (file.Intersect(Path.GetInvalidFileNameChars()).Any() _
                        OrElse _
                        directory.Intersect(Path.GetInvalidPathChars()).Any())
        End If

    End Function

Upvotes: 1

Public Escobar
Public Escobar

Reputation: 31

Ok. Good ideas. But manual iteration of 'invalid' chars is not the best way, when you work with thousands of files.

Public BadChars() As Char = IO.Path.GetInvalidFileNameChars

For m = 0 To thousands_of_files - 1
    '..
    if currFile.Name.ToCharArray.Intersect(BadChars).Count > 1 Then
         ' the Name is invalid - what u gonna do? =)
    end if
    '..
    '..
Next

Upvotes: 0

Hedi Guizani
Hedi Guizani

Reputation: 21

try this

Public Function IsValidFileName(ByVal fn As String) As Boolean
    Try
        Dim fi As New IO.FileInfo(fn)
    Catch ex As Exception
        Return False
    End Try
    Return True
End Function

Upvotes: 1

Paul Farry
Paul Farry

Reputation: 4768

Even though this is quite old, it's still valid, and I ended up here looking for the solution to how to check the filename for invalid characters. I looked at the accepted answer and found a few holes.

Hopefully these modifications are of some use to someone else.

Public Function FilenameIsOK(ByVal fileNameAndPath As String) As Boolean
    Dim fileName As String = String.Empty
    Dim theDirectory As String = fileNameAndPath

    Dim p As Char = Path.DirectorySeparatorChar

    Dim splitPath() As String
    splitPath = fileNameAndPath.Split(p)
    If splitPath.Length > 1 Then
        fileName = splitPath(splitPath.Length - 1)
        theDirectory = String.Join(p, splitPath, 0, splitPath.Length - 1)
    End If

    For Each c As Char In Path.GetInvalidFileNameChars()
        If fileName.Contains(c) Then
            Return False
        End If
    Next

    For Each c As Char In Path.GetInvalidPathChars()
        If theDirectory.Contains(c) Then
            Return False
        End If
    Next
    Return True
End Function

Upvotes: 2

Bob King
Bob King

Reputation: 25856

How about Path.GetInvalidFileNameChars and Path.GetInvalidPathChars?

Public Shared Function FilenameIsOK(ByVal fileNameAndPath as String) as Boolean
    Dim fileName = Path.GetFileName(fileNameAndPath)
    Dim directory = Path.GetDirectoryName(fileNameAndPath)
    For each c in Path.GetInvalidFileNameChars()
        If fileName.Contains(c) Then
            Return False
        End If
    Next
    For each c in Path.GetInvalidPathChars()
        If directory.Contains(c) Then
            Return False
        End If
    Next
    Return True
End Function

Upvotes: 10

TWA
TWA

Reputation: 12816

It is a regex and C# but:

using System;
using System.Text.RegularExpressions;

/// <summary>
/// Gets whether the specified path is a valid absolute file path.
/// </summary>
/// <param name="path">Any path. OK if null or empty.</param>
static public bool IsValidPath( string path )
{
    Regex r = new Regex( @"^(([a-zA-Z]\:)|(\\))(\\{1}|((\\{1})[^\\]([^/:*?<>""|]*))+)$" );
    return r.IsMatch( path );
}

Upvotes: 2

Paul Sonier
Paul Sonier

Reputation: 39480

Frankly, I'd just use the FileInfo object built in to .NET, and check for an exception for invalidity. See this reference for details.

Upvotes: 1

Related Questions