In C# check that filename is *possibly* valid (not that it exists)



Answers

You can get a list of invalid characters from Path.GetInvalidPathChars and GetInvalidFileNameChars as discussed in this question.

As noted by jberger, there some other characters which are not included in the response from this method. For much more details of the windows platform, take a look at Naming Files, Paths and Namespaces on MSDN,

As Micah points out, there is Directory.GetLogicalDrives to get a list of valid drives.

Question

This question already has an answer here:

Is there a method in the System.IO namespace that checks the validity of a filename?

For example, C:\foo\bar would validate and :"~-* would not

Or a little trickier, X:\foo\bar would validate is there is an X: drive on the system, but wouldn't otherwise.

I suppose I could write such a method myself, but I'm more interested in a built-in one.







I've had luck using regular expressions as others have shown.

One thing to keep in mind is that Windows at least prohibits some filenames that otherwise containlegal characters. A few come to mind: com, nul, prn.

I don't have it with me now, but I have a regex that takes these filename into consideration. If you want I can post it, otherwise I'm sure you can find it the same way I did: Google.

-Jay




Try out this method which would try to cover for all the possible Exceptions scenarios. It would work for almost all the Windows related Paths.

/// <summary>
/// Validate the Path. If path is relative append the path to the project directory by default.
/// </summary>
/// <param name="path">Path to validate</param>
/// <param name="RelativePath">Relative path</param>
/// <param name="Extension">If want to check for File Path</param>
/// <returns></returns>
private static bool ValidateDllPath(ref string path, string RelativePath = "", string Extension = "") {
    // Check if it contains any Invalid Characters.
    if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1) {
        try {
            // If path is relative take %IGXLROOT% as the base directory
            if (!Path.IsPathRooted(path)) {
                if (string.IsNullOrEmpty(RelativePath)) {
                    // Exceptions handled by Path.GetFullPath
                    // ArgumentException path is a zero-length string, contains only white space, or contains one or more of the invalid characters defined in GetInvalidPathChars. -or- The system could not retrieve the absolute path.
                    // 
                    // SecurityException The caller does not have the required permissions.
                    // 
                    // ArgumentNullException path is null.
                    // 
                    // NotSupportedException path contains a colon (":") that is not part of a volume identifier (for example, "c:\"). 
                    // PathTooLongException The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.

                    // RelativePath is not passed so we would take the project path 
                    path = Path.GetFullPath(RelativePath);

                } else {
                    // Make sure the path is relative to the RelativePath and not our project directory
                    path = Path.Combine(RelativePath, path);
                }
            }

            // Exceptions from FileInfo Constructor:
            //   System.ArgumentNullException:
            //     fileName is null.
            //
            //   System.Security.SecurityException:
            //     The caller does not have the required permission.
            //
            //   System.ArgumentException:
            //     The file name is empty, contains only white spaces, or contains invalid characters.
            //
            //   System.IO.PathTooLongException:
            //     The specified path, file name, or both exceed the system-defined maximum
            //     length. For example, on Windows-based platforms, paths must be less than
            //     248 characters, and file names must be less than 260 characters.
            //
            //   System.NotSupportedException:
            //     fileName contains a colon (:) in the middle of the string.
            FileInfo fileInfo = new FileInfo(path);

            // Exceptions using FileInfo.Length:
            //   System.IO.IOException:
            //     System.IO.FileSystemInfo.Refresh() cannot update the state of the file or
            //     directory.
            //
            //   System.IO.FileNotFoundException:
            //     The file does not exist.-or- The Length property is called for a directory.
            bool throwEx = fileInfo.Length == -1;

            // Exceptions using FileInfo.IsReadOnly:
            //   System.UnauthorizedAccessException:
            //     Access to fileName is denied.
            //     The file described by the current System.IO.FileInfo object is read-only.-or-
            //     This operation is not supported on the current platform.-or- The caller does
            //     not have the required permission.
            throwEx = fileInfo.IsReadOnly;

            if (!string.IsNullOrEmpty(Extension)) {
                // Validate the Extension of the file.
                if (Path.GetExtension(path).Equals(Extension, StringComparison.InvariantCultureIgnoreCase)) {
                    // Trim the Library Path
                    path = path.Trim();
                    return true;
                } else {
                    return false;
                }
            } else {
                return true;

            }
        } catch (ArgumentNullException) {
            //   System.ArgumentNullException:
            //     fileName is null.
        } catch (System.Security.SecurityException) {
            //   System.Security.SecurityException:
            //     The caller does not have the required permission.
        } catch (ArgumentException) {
            //   System.ArgumentException:
            //     The file name is empty, contains only white spaces, or contains invalid characters.
        } catch (UnauthorizedAccessException) {
            //   System.UnauthorizedAccessException:
            //     Access to fileName is denied.
        } catch (PathTooLongException) {
            //   System.IO.PathTooLongException:
            //     The specified path, file name, or both exceed the system-defined maximum
            //     length. For example, on Windows-based platforms, paths must be less than
            //     248 characters, and file names must be less than 260 characters.
        } catch (NotSupportedException) {
            //   System.NotSupportedException:
            //     fileName contains a colon (:) in the middle of the string.
        } catch (FileNotFoundException) {
            // System.FileNotFoundException
            //  The exception that is thrown when an attempt to access a file that does not
            //  exist on disk fails.
        } catch (IOException) {
            //   System.IO.IOException:
            //     An I/O error occurred while opening the file.
        } catch (Exception) {
            // Unknown Exception. Might be due to wrong case or nulll checks.
        }
    } else {
        // Path contains invalid characters
    }
    return false;
}



Thought I would post a solution I cobbled together from bits of answers I found after searching for a robust solution to the same problem. Hopefully it helps someone else.

using System;
using System.IO;
//..

       public static bool ValidateFilePath(string path,bool RequireDirectory,bool IncludeFileName,bool RequireFileName=false)
    {
        if (string.IsNullOrEmpty(path)) {return false;}
        string root = null; ;
        string directory=null;
        string filename=null;
        try
        {
            //throw ArgumentException   - The path parameter contains invalid characters, is empty, or contains only white spaces.
            root = Path.GetPathRoot(path);
            //throw ArgumentException   - path contains one or more of the invalid characters defined in GetInvalidPathChars.
            //    -or- String.Empty was passed to path.
            directory = Path.GetDirectoryName(path);
            //path contains one or more of the invalid characters defined in GetInvalidPathChars
            if (IncludeFileName) { filename = Path.GetFileName(path); }
        }
        catch (ArgumentException)
        {
            return false;
        }
        //null if path is null, or an empty string if path does not contain root directory information
        if (String.IsNullOrEmpty(root)){return false;}
        //null if path denotes a root directory or is null. Returns String.Empty if path does not contain directory information
        if (String.IsNullOrEmpty(directory)) { return false; }
        if (RequireFileName)
        {
            //f the last character of path is a directory or volume separator character, this method returns String.Empty
            if (String.IsNullOrEmpty(filename)) { return false; }
            //check for illegal chars in filename
            if (filename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0){ return false;}
        }
        return true;
    }



You could make use the System.Uri class. The Uri class isn't just useful for web URLs, it also handles file system paths as well. Use the Uri.TryCreate method to find if the path is rooted then use the IsLoopback property to determine if the Uri references the local machine.

Here is a simple method which determines if a string is a valid, local, and rooted file path.

public bool IsPathValidRootedLocal(String pathString) {
    Uri pathUri;
    Boolean isValidUri = Uri.TryCreate(pathString, UriKind.Absolute, out pathUri);
    return isValidUri && pathUri != null && pathUri.IsLoopback;
}

I am confident this will work.




Think it's too late to answer but... :) in case of path with volume name you could write something like this:

using System;
using System.Linq;
using System.IO;

// ...

var drives = Environment.GetLogicalDrives();
var invalidChars = Regex.Replace(new string(Path.GetInvalidFileNameChars()), "[\\\\/]", "");
var drive = drives.FirstOrDefault(d => filePath.StartsWith(d));
if (drive != null) {
    var fileDirPath = filePath.Substring(drive.Length);
    if (0 < fileDirPath.Length) {
        if (fileDirPath.IndexOfAny(invalidChars.ToCharArray()) == -1) {
            if (Path.Combine(drive, fileDirPath) != drive) {
                // path correct and we can proceed
            }
        }
    }
}



Links