Controlla se una stringa è un percorso di directory (cartella) di Windows valido


84

Sto cercando di determinare se una stringa inserita da un utente è valida per rappresentare un percorso a una cartella. Per valido, intendo formattato correttamente.

Nella mia applicazione, la cartella rappresenta una destinazione di installazione. A condizione che il percorso della cartella sia valido, voglio determinare se la cartella esiste e crearla in caso contrario.

Attualmente sto usando IO.Directory.Exists( String path ). Trovo che funzioni bene tranne quando l'utente non formatta correttamente la stringa. Quando ciò accade, questo metodo restituirà false che indica che la cartella non esiste. Ma questo è un problema perché non sarò in grado di creare la cartella in seguito.

Dal mio googling ho trovato un suggerimento per utilizzare un'espressione regolare per verificare se il formato è corretto. Non ho esperienza con le espressioni regolari e mi chiedo se questo sia un approccio praticabile. Ecco cosa ho trovato:

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

Un test di espressione regolare in combinazione con Directory.Exists(), mi darebbe un metodo abbastanza buono per verificare se il percorso è valido e se esiste? So che questo varierà in base al sistema operativo e ad altri fattori, ma il programma è destinato solo agli utenti Windows .


1
Se non crea la directory dopo che Directory.Exists restituisce false, non è un'indicazione abbastanza buona che l'utente ha fornito un input errato?
Robert Harvey,



2
@RobertHo visto quella domanda e non ha fornito una risposta specifica diversa dalle regole generali. La seconda risposta più alta non copriva la formattazione ma solo i caratteri non validi. Anche il metodo Directory.Exists può restituire false, ma poiché desidero l'opzione di creare la cartella sul posto non posso semplicemente seguire quello.
Pudpuduk

@Robert Sul secondo argomento che hai collegato - digitando una singola parola passerebbe comunque la convalida data nelle risposte a quella domanda.
Pudpuduk

Risposte:


119

Chiama Path.GetFullPath; genererà eccezioni se il percorso non è valido.

Per non consentire percorsi relativi (come Word), chiama Path.IsPathRooted.


Sapevo che c'era qualcosa di più semplice! E grazie, non ho pensato al problema dei percorsi relativi all'essere relativi.
Pudpuduk

3
Grazie SLaks. Ho visto molti duplicati e fatto molte ricerche su Google (in più di un'occasione), ma questa è la prima volta che vedo una buona risposta a questa particolare domanda.
Robert Harvey,

5
Path.GetFullPath ("con.txt") è un nome di file valido.
Christoffer

8
@Slaks Questo è troppo vecchio per lasciare un commento, ma voglio comunque lasciarne uno qui per il motivo per cui ti ho dato il mio voto -1. Path.GetFullPath () sembra funzionare bene, ma cosa succede se il percorso è: "Z: \\\\\\\\ Hi \\\\\\ There", non è un percorso assoluto valido ma Path.GetFullPath (...) fornisce il risultato: Z: \ Hi \ There e non viene sollevata alcuna eccezione. Ho dovuto cambiarlo un po 'confrontando la stringa restituita da GetFullPath () e la stringa originale in questo modo: private bool IsPathValid (string path) {try {string fullPath = Path.GetFullPath (path); return fullPath == path; } catch {return false;}}
King King

4
@ KingKing Da questa risposta di Linux su unix.stackexchange.com: "Sono consentite più barre e sono equivalenti a una singola barra .." Ho osservato lo stesso su Windows (sebbene le barre iniziali in un percorso UNC possano essere trattate in modo diverso). Per la prova di questo, in un prompt dei comandi, provate questo: cd C:\\\\\\\Windows\\\\\\\System32. Per Windows, non riesco a trovare una fonte autorevole che documenti questo comportamento, ma ovviamente sarebbe gradito un puntatore a uno.
DavidRR

18

In realtà non sono d'accordo con SLaks. Quella soluzione non ha funzionato per me. L'eccezione non è avvenuta come previsto. Ma questo codice ha funzionato per me:

if(System.IO.Directory.Exists(path))
{
    ...
}

64
Un percorso valido non è necessariamente una directory che esiste ... che è esattamente il problema posto qui
Benlitz

2
la domanda era correlata alla convalida della stringa del percorso, un percorso che potrebbe non esistere.
Mubashar

Penso che in questo modo sia corretto. Non dovrebbero essere previste eccezioni. Questo metodo controlla anche i caratteri errati nel percorso specificato.
Eugene Maksimov

Questa condizione genererà un'eccezione se il "percorso" non è trovato un percorso reale poiché Directory.Exists richiede un percorso valido.
M. Fawad Surosh

Risposta completamente sbagliata! Mi chiedo come abbia ricevuto 32 voti positivi (al momento). Devono essere persone che stavano guardando nel posto sbagliato per il problema che stavano affrontando, e si sono imbattuti in questo.
Sнаđошƒаӽ

13

Path.GetFullPath fornisce solo le eccezioni seguenti

Il percorso ArgumentException è una stringa di lunghezza zero, contiene solo spazi vuoti o contiene uno o più caratteri non validi definiti in GetInvalidPathChars. - oppure - Il sistema non è riuscito a recuperare il percorso assoluto.

SecurityException Il chiamante non dispone delle autorizzazioni richieste.

Il percorso ArgumentNullException è null.

Il percorso NotSupportedException contiene i due punti (":") che non fanno parte di un identificatore di volume (ad esempio, "c: \").

PathTooLongException Il percorso, il nome file o entrambi specificati superano la lunghezza massima definita dal sistema. Ad esempio, su piattaforme basate su Windows, i percorsi devono contenere meno di 248 caratteri e i nomi dei file devono contenere meno di 260 caratteri.

Un modo alternativo consiste nell'usare quanto segue:

/// <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;
}

9

Ecco una soluzione che sfrutta l'uso di Path.GetFullPath come consigliato nella risposta di @SLaks .

Nel codice che includo qui, nota che IsValidPath(string path)è progettato in modo tale che il chiamante non deve preoccuparsi della gestione delle eccezioni .

Potresti anche scoprire che il metodo che chiama TryGetFullPath(...),, ha anche valore da solo quando desideri tentare in sicurezza di ottenere un percorso assoluto .

/// <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;
}

6

Usa questo codice

string DirectoryName = "Sample Name For Directory Or File";
Path.GetInvalidFileNameChars()
  .Where(x => DirectoryName.Contains(x))
  .Count() > 0 || DirectoryName == "con"

4
Codice leggermente più breve che realizza la stessa cosa: Path.GetInvalidFileNameChars().Any(DirectoryName.Contains) || DirectoryName == "con"
bsegraves

2
@nawfal Indeed. Da Naming Files, Paths, and Namespaces on MSDN: "Non utilizzare i seguenti nomi riservati per il nome di un file: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 e LPT9. Evita inoltre questi nomi seguiti immediatamente da un'estensione; ad esempio, NUL.txt non è consigliato. Per ulteriori informazioni, consulta Spazi dei nomi . "
DavidRR

Questo "approccio da lista nera" non funziona su tutti i sistemi Windows, ad esempio quando vengono visualizzati i pittogrammi: en.wikipedia.org/wiki/Miscellaneous_Symbols_and_Pictographs
gennaio

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;
    }

3

Non ho avuto problemi con questo codice:

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;
}

Ad esempio, questi restituirebbero false:

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);

E questi tornerebbero veri:

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);

3

Una soluzione più semplice, indipendente dal sistema operativo:

Vai avanti e prova a creare la directory effettiva; se c'è un problema o il nome non è valido, il sistema operativo si lamenterà automaticamente e verrà lanciato il codice.

public static class PathHelper
{
    public static void ValidatePath(string path)
    {
        if (!Directory.Exists(path))
            Directory.CreateDirectory(path).Delete();
    }
}

Utilizzo:

try
{
    PathHelper.ValidatePath(path);
}
catch(Exception e)
{
    // handle exception
}

Directory.CreateDirectory() eseguirà automaticamente tutte le seguenti situazioni:

System.IO.IOException:
la directory specificata da path è un file. - oppure - Il nome di rete non è noto.

System.UnauthorizedAccessException:
il chiamante non dispone dell'autorizzazione richiesta.

System.ArgumentException:
path è una stringa di lunghezza zero, contiene solo spazi vuoti o contiene uno o più caratteri non validi. È possibile eseguire una query per caratteri non validi utilizzando il metodo System.IO.Path.GetInvalidPathChars. -oppure- il percorso è preceduto da o contiene solo un carattere di due punti (:).

System.ArgumentNullException: il
percorso è nullo.

System.IO.PathTooLongException:
il percorso, il nome file o entrambi specificati superano la lunghezza massima definita dal sistema.

System.IO.DirectoryNotFoundException:
il percorso specificato non è valido (ad esempio, si trova su un'unità non mappata).

System.NotSupportedException: il
percorso contiene un carattere di due punti (:) che non fa parte di un'etichetta di unità ("C:").

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.