Überprüfen Sie, ob eine Zeichenfolge ein gültiger Pfad für das Windows-Verzeichnis (Ordner) ist

84

Ich versuche festzustellen, ob eine von einem Benutzer eingegebene Zeichenfolge für die Darstellung eines Pfads zu einem Ordner gültig ist. Mit gültig meine ich richtig formatiert.

In meiner Anwendung repräsentiert der Ordner ein Installationsziel. Vorausgesetzt, der Ordnerpfad ist gültig, möchte ich feststellen, ob der Ordner vorhanden ist, und ihn erstellen, wenn dies nicht der Fall ist.

Ich benutze gerade IO.Directory.Exists( String path ). Ich finde, dass dies gut funktioniert, außer wenn der Benutzer die Zeichenfolge nicht richtig formatiert. In diesem Fall gibt diese Methode false zurück, was darauf hinweist, dass der Ordner nicht vorhanden ist. Dies ist jedoch ein Problem, da ich den Ordner anschließend nicht mehr erstellen kann.

Beim Googeln habe ich einen Vorschlag gefunden, einen regulären Ausdruck zu verwenden, um zu überprüfen, ob das Format korrekt ist. Ich habe keine Erfahrung mit regulären Ausdrücken und frage mich, ob dies ein praktikabler Ansatz ist. Folgendes habe ich gefunden:

Regex r = new Regex( @"^(([a-zA-Z]\:)|(\\))(\\{1}|((\\{1})[^\\]([^/:*?<>""|]*))+)$" );
return r.IsMatch( path );

Würde Directory.Exists()mir ein Test für reguläre Ausdrücke in Kombination mit eine ausreichend gute Methode geben, um zu überprüfen, ob der Pfad gültig ist und ob er existiert? Ich weiß, dass dies mit dem Betriebssystem und anderen Faktoren variieren wird, aber das Programm richtet sich nur an Windows- Benutzer.

Pudpuduk
quelle
1
Wenn das Verzeichnis nicht erstellt wird, nachdem Directory.Exists false zurückgibt, ist das nicht ein ziemlich guter Hinweis darauf, dass der Benutzer eine schlechte Eingabe bereitgestellt hat?
Robert Harvey
2
@ Robert Ich habe diese Frage gesehen und sie lieferte keine spezifische Antwort außer den allgemeinen Regeln. Die zweithöchste Antwort betraf nicht die Formatierung, sondern nur ungültige Zeichen. Auch die Directory.Exists-Methode kann false zurückgeben, aber da ich die Option zum Erstellen des Ordners an Ort und Stelle haben möchte, kann ich nicht einfach so vorgehen.
Pudpuduk
@Robert Beim zweiten Thema, das Sie verlinkt haben, besteht die Eingabe eines einzelnen Wortes weiterhin in den Antworten, die in den Antworten auf diese Frage angegeben sind.
Pudpuduk

Antworten:

116

Rufen Sie an Path.GetFullPath; Es werden Ausnahmen ausgelöst, wenn der Pfad ungültig ist.

WordRufen Sie auf, um relative Pfade (z. B. ) nicht zuzulassen Path.IsPathRooted.

SLaks
quelle
Ich wusste, dass es etwas Einfacheres gibt! Und danke, ich habe nicht an das Problem gedacht, dass Pfade relativ sind.
Pudpuduk
2
Danke SLaks. Ich habe viele Duplikate gesehen und viele Google-Suchen durchgeführt (mehr als einmal), aber dies ist das erste Mal, dass ich eine gute Antwort auf diese spezielle Frage sehe.
Robert Harvey
5
Path.GetFullPath ("con.txt") ist ein gültiger Dateiname.
Christoffer
8
@ Slaks Dies ist zu alt, um einen Kommentar zu hinterlassen, aber ich möchte immer noch einen hier hinterlassen, aus dem Grund, dass ich Ihnen meine Stimme von -1 gegeben habe. Path.GetFullPath () scheint in Ordnung zu funktionieren, aber was ist, wenn der Pfad lautet: "Z: \\\\\\\\ Hi \\\\\\ There", es ist kein gültiger absoluter Pfad, sondern der Path.GetFullPath (...) gibt das Ergebnis aus: Z: \ Hi \ Es wird keine Ausnahme ausgelöst. Ich musste es ein wenig ändern, indem ich die von GetFullPath () zurückgegebene Zeichenfolge mit der ursprünglichen Zeichenfolge wie folgt verglich: private bool IsPathValid (Zeichenfolgenpfad) {try {Zeichenfolge fullPath = Path.GetFullPath (Pfad); return fullPath == path; } catch {return false;}}
König König
4
@KingKing Aus dieser Linux-Antwort auf unix.stackexchange.com: "Mehrere Schrägstriche sind zulässig und entsprechen einem einzelnen Schrägstrich." Ich habe dasselbe unter Windows beobachtet (obwohl die führenden Schrägstriche in einem UNC-Pfad möglicherweise unterschiedlich behandelt werden). Versuchen Sie dies an einer Eingabeaufforderung, um dies zu beweisen : cd C:\\\\\\\Windows\\\\\\\System32. Für Windows kann ich keine maßgebliche Quelle finden, die dieses Verhalten dokumentiert, würde aber natürlich einen Zeiger auf eine begrüßen.
DavidRR
19

Ich bin eigentlich nicht einverstanden mit SLaks. Diese Lösung hat bei mir nicht funktioniert. Die Ausnahme ist nicht wie erwartet aufgetreten. Aber dieser Code hat bei mir funktioniert:

if(System.IO.Directory.Exists(path))
{
    ...
}
Scott Shaw-Smith
quelle
61
Ein gültiger Pfad ist nicht unbedingt ein Verzeichnis, das existiert ... genau das ist das Problem, das hier gestellt wird
Benlitz
1
Die Frage bezog sich auf die Validierung der Pfadzeichenfolge, ein Pfad, der möglicherweise nicht vorhanden ist.
Mubashar
Ich denke, dieser Weg ist richtig. Ausnahmen sind nicht zu erwarten. Diese Methode überprüft auch falsche Zeichen im angegebenen Pfad.
Eugene Maksimov
Diese Bedingung löst selbst eine Ausnahme aus, wenn festgestellt wird, dass der "Pfad" kein realer Pfad ist, da Directory.Exists einen gültigen Pfad erfordert.
M. Fawad Surosh
Völlig falsche Antwort! Ich frage mich, wie es 32 Upvotes erhalten hat (ab sofort). Muss von Leuten sein, die nach dem falschen Ort für das Problem gesucht haben, mit dem sie konfrontiert waren, und sie sind darauf gestoßen.
Sнаđошƒаӽ
13

Path.GetFullPath gibt nur die folgenden Ausnahmen an

Der ArgumentException-Pfad ist eine Zeichenfolge mit der Länge Null, enthält nur Leerzeichen oder enthält eines oder mehrere der in GetInvalidPathChars definierten ungültigen Zeichen. -oder- Das System konnte den absoluten Pfad nicht abrufen.

SecurityException Der Anrufer verfügt nicht über die erforderlichen Berechtigungen.

Der ArgumentNullException-Pfad ist null.

Der NotSupportedException-Pfad enthält einen Doppelpunkt (":"), der nicht Teil einer Datenträgerkennung ist (z. B. "c: \").

PathTooLongException Der angegebene Pfad, Dateiname oder beide überschreiten die vom System definierte maximale Länge. Auf Windows-basierten Plattformen müssen Pfade beispielsweise weniger als 248 Zeichen und Dateinamen weniger als 260 Zeichen enthalten.

Alternativ können Sie Folgendes verwenden:

/// <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;
}
vKillusion
quelle
9

Hier ist eine Lösung, die die Verwendung von Path.GetFullPath nutzt, wie in der Antwort von @SLaks empfohlen .

Beachten Sie in dem Code, den ich hier einbinde, IsValidPath(string path)dass der Anrufer sich nicht um die Ausnahmebehandlung kümmern muss .

Möglicherweise stellen Sie auch fest, dass die von ihr aufgerufene Methode TryGetFullPath(...)auch für sich allein von Nutzen ist, wenn Sie sicher versuchen möchten, einen absoluten Pfad zu erhalten .

/// <summary>
/// Gets a value that indicates whether <paramref name="path"/>
/// is a valid path.
/// </summary>
/// <returns>Returns <c>true</c> if <paramref name="path"/> is a
/// valid path; <c>false</c> otherwise. Also returns <c>false</c> if
/// the caller does not have the required permissions to access
/// <paramref name="path"/>.
/// </returns>
/// <seealso cref="Path.GetFullPath"/>
/// <seealso cref="TryGetFullPath"/>
public static bool IsValidPath(string path)
{
    string result;
    return TryGetFullPath(path, out result);
}

/// <summary>
/// Returns the absolute path for the specified path string. A return
/// value indicates whether the conversion succeeded.
/// </summary>
/// <param name="path">The file or directory for which to obtain absolute
/// path information.
/// </param>
/// <param name="result">When this method returns, contains the absolute
/// path representation of <paramref name="path"/>, if the conversion
/// succeeded, or <see cref="String.Empty"/> if the conversion failed.
/// The conversion fails if <paramref name="path"/> is null or
/// <see cref="String.Empty"/>, or is not of the correct format. This
/// parameter is passed uninitialized; any value originally supplied
/// in <paramref name="result"/> will be overwritten.
/// </param>
/// <returns><c>true</c> if <paramref name="path"/> was converted
/// to an absolute path successfully; otherwise, false.
/// </returns>
/// <seealso cref="Path.GetFullPath"/>
/// <seealso cref="IsValidPath"/>
public static bool TryGetFullPath(string path, out string result)
{
    result = String.Empty;
    if (String.IsNullOrWhiteSpace(path)) { return false; }
    bool status = false;

    try
    {
        result = Path.GetFullPath(path);
        status = true;
    }
    catch (ArgumentException) { }
    catch (SecurityException) { }
    catch (NotSupportedException) { }
    catch (PathTooLongException) { }

    return status;
}
DavidRR
quelle
6

Verwenden Sie diesen Code

string DirectoryName = "Sample Name For Directory Or File";
Path.GetInvalidFileNameChars()
  .Where(x => DirectoryName.Contains(x))
  .Count() > 0 || DirectoryName == "con"
user1508188
quelle
4
Etwas kürzerer Code, der dasselbe erreicht: Path.GetInvalidFileNameChars().Any(DirectoryName.Contains) || DirectoryName == "con"
bsegraves
2
@nawfal In der Tat. Aus dem Benennen von Dateien, Pfaden und Namespaces auf MSDN: "Verwenden Sie nicht die folgenden reservierten Namen für den Namen einer Datei: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 und LPT9. Vermeiden Sie auch diese Namen, gefolgt von einer Erweiterung. Beispiel: NUL.txt wird nicht empfohlen. Weitere Informationen finden Sie unter Namespaces . "
DavidRR
Dieser "Blacklist-Ansatz" funktioniert nicht auf jedem Windows-System, zum Beispiel, wenn ein Piktogramm angezeigt wird: en.wikipedia.org/wiki/Miscellaneous_Symbols_and_Pictographs
Januar
4
    private bool IsValidPath(string path)
    {
        Regex driveCheck = new Regex(@"^[a-zA-Z]:\\$");
        if (!driveCheck.IsMatch(path.Substring(0, 3))) return false;
        string strTheseAreInvalidFileNameChars = new string(Path.GetInvalidPathChars());
        strTheseAreInvalidFileNameChars += @":/?*" + "\"";
        Regex containsABadCharacter = new Regex("[" + Regex.Escape(strTheseAreInvalidFileNameChars) + "]");
        if (containsABadCharacter.IsMatch(path.Substring(3, path.Length - 3)))
            return false;

        DirectoryInfo dir = new DirectoryInfo(Path.GetFullPath(path));
        if (!dir.Exists)
            dir.Create();
        return true;
    }
Alex Jolig
quelle
3

Ich hatte keine Probleme mit diesem Code:

private bool IsValidPath(string path, bool exactPath = true)
{
    bool isValid = true;

    try
    {
        string fullPath = Path.GetFullPath(path);

        if (exactPath)
        {
            string root = Path.GetPathRoot(path);
            isValid = string.IsNullOrEmpty(root.Trim(new char[] { '\\', '/' })) == false;
        }
        else
        {
            isValid = Path.IsPathRooted(path);
        }
    }
    catch(Exception ex)
    {
        isValid = false;
    }

    return isValid;
}

Zum Beispiel würden diese false zurückgeben:

IsValidPath("C:/abc*d");
IsValidPath("C:/abc?d");
IsValidPath("C:/abc\"d");
IsValidPath("C:/abc<d");
IsValidPath("C:/abc>d");
IsValidPath("C:/abc|d");
IsValidPath("C:/abc:d");
IsValidPath("");
IsValidPath("./abc");
IsValidPath("/abc");
IsValidPath("abc");
IsValidPath("abc", false);

Und diese würden wahr zurückkehren:

IsValidPath(@"C:\\abc");
IsValidPath(@"F:\FILES\");
IsValidPath(@"C:\\abc.docx\\defg.docx");
IsValidPath(@"C:/abc/defg");
IsValidPath(@"C:\\\//\/\\/\\\/abc/\/\/\/\///\\\//\defg");
IsValidPath(@"C:/abc/def~`!@#$%^&()_-+={[}];',.g");
IsValidPath(@"C:\\\\\abc////////defg");
IsValidPath(@"/abc", false);
Dao-Sucher
quelle