Перевірте, чи є рядок дійсним шляхом до каталогу (папки) Windows


84

Я намагаюся визначити, чи введений користувачем рядок є дійсним для представлення шляху до папки. Під дійсним я маю на увазі правильно відформатований.

У моєму додатку папка являє собою пункт встановлення. За умови, що шлях до папки є дійсним, я хочу визначити, чи існує папка, і створити її, якщо її немає.

В даний час я використовую IO.Directory.Exists( String path ). Я вважаю, що це працює нормально, за винятком випадків, коли користувач неправильно форматує рядок. Коли це станеться, цей метод поверне значення false, що вказує на те, що папка не існує. Але це проблема, оскільки згодом я не зможу створити папку.

З мого гугління я знайшов пропозицію використовувати регулярний вираз, щоб перевірити, чи правильний формат. Я не маю досвіду роботи з регулярними виразами, і мені цікаво, чи це життєздатний підхід. Ось що я знайшов:

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

Тест регулярних виразів у поєднанні з Directory.Exists(), дасть мені достатньо хороший метод, щоб перевірити, чи є шлях дійсним і чи існує? Я знаю, що це буде залежати від ОС та інших факторів, але програма орієнтована лише на користувачів Windows .


1
Якщо він не може створити каталог після того, як Directory.Exists повертає false, чи не є це досить хорошим показником того, що користувач надав неправильний ввід?
Роберт Харві,



2
@RobertЯ бачив це запитання, і воно не дало конкретної відповіді, крім загальних правил. Друга найвища відповідь не стосувалася форматування, а лише недійсні символи. Також метод Directory.Exists може повертати false, але оскільки я хочу можливість створення папки на місці, я не можу просто піти на це.
Пудпудук,

@Robert Щодо другої теми, яку ви зв’язали - введення одного слова все одно пройде перевірку, вказану у відповідях на це питання.
Пудпудук,

Відповіді:


116

Дзвінок Path.GetFullPath; він видасть винятки, якщо шлях недійсний.

Щоб заборонити відносні шляхи (наприклад Word), зателефонуйте Path.IsPathRooted.


Я знав, що є щось простіше! І спасибі, я не думав про проблему шляхів-відношення.
Пудпудук,

2
Дякую SLaks. Я бачив багато дублікатів і робив багато пошуків у Google (неодноразово), але вперше я побачив гарну відповідь на це конкретне питання.
Роберт Харві,

5
Path.GetFullPath ("con.txt") - дійсне ім'я файлу.
Christoffer

8
@Slaks Це занадто давно, щоб залишати коментар, але я все одно хочу залишити його тут з тієї причини, що дав вам свій голос -1. Path.GetFullPath (), здається, працює нормально, але що, якщо шлях такий: "Z: \\\\\\\ Привіт \\\\\\ Там", це не дійсний абсолютний шлях, а Path.GetFullPath (...) видає результат: Z: \ Hi \ Там і немає винятку. Мені довелося його трохи змінити, порівнявши рядок, який повертає GetFullPath (), та оригінальний рядок, такий: private bool IsPathValid (рядок шляху) {try {рядок fullPath = Path.GetFullPath (шлях); повернути fullPath == шлях; } catch {return false;}}
Кінг Кінг

4
@KingKing З цієї відповіді Linux на unix.stackexchange.com: " Допускається декілька скісних слєшів , що еквівалентно одній косою рисою .." Я спостерігав те саме в Windows (хоча провідні слєші в шляху UNC можуть трактуватися по-різному). Для доказу цього, в командному рядку, спробуйте наступне: cd C:\\\\\\\Windows\\\\\\\System32. Для Windows я не можу знайти авторитетного джерела, яке б документувало таку поведінку, але, звичайно, вітається вказівник на нього.
DavidRR

20

Я насправді не згоден із SLaks. Це рішення для мене не спрацювало. Виняток стався не так, як очікувалося. Але цей код працював для мене:

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

62
Дійсний шлях - це не обов’язково каталог, який існує ... і саме тут
задається

1
Питання було пов'язане з валідацією рядка шляху, шляху, який міг би не існувати.
Mubashar

Я вважаю, що цей шлях правильний. Не слід очікувати винятків. Цей метод також перевіряє неправильні символи в заданому шляху.
Євген Максимов

Ця умова сама по собі викличе виняток, якщо "шлях" виявиться не реальним шляхом, оскільки Directory.Exists вимагає дійсний шлях.
М. Фавад Сурош

Зовсім неправильна відповідь! Цікаво, як він отримав 32 голоси за (на даний момент). Мають бути люди, які шукали неправильне місце для вирішення проблеми, з якою вони зіткнулися, і вони натрапили на це.
Sнаđошƒаӽ

13

Path.GetFullPath дає лише винятки нижче

Шлях ArgumentException - це рядок нульової довжини, містить лише пробіли або містить один або кілька недійсних символів, визначених у GetInvalidPathChars. -ілі- Система не змогла отримати абсолютний шлях.

SecurityException Абонент не має необхідних дозволів.

Шлях ArgumentNullException має значення null.

Шлях NotSupportedException містить двокрапку (":"), яка не є частиною ідентифікатора тома (наприклад, "c: \").

PathTooLongException Вказаний шлях, ім'я файлу або обидва вони перевищують визначену системою максимальну довжину. Наприклад, на платформах під керуванням Windows шляхи повинні мати менше 248 символів, а імена файлів - менше 260 символів.

Альтернативний спосіб - використовувати наступне:

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

Ось рішення, яке використовує використання Path.GetFullPath, як рекомендовано у відповіді @SLaks .

У коді, який я тут включаю, зверніть увагу, що IsValidPath(string path)він розроблений таким чином, що абоненту не доведеться турбуватися про обробку винятків .

Ви також можете виявити, що метод, який він викликає, TryGetFullPath(...)також має достоїнства сам по собі, коли ви хочете безпечно спробувати отримати абсолютний шлях .

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

Використовуйте цей Кодекс

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

4
Трохи коротший код, який виконує те саме: Path.GetInvalidFileNameChars().Any(DirectoryName.Contains) || DirectoryName == "con"
bsegraves

2
@nawfal Справді. З іменування файлів, шляхів та просторів імен на MSDN: "Не використовуйте такі зарезервовані імена для імені файлу: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 та LPT9. Також уникайте цих назв, за якими слідує розширення; наприклад, не рекомендується NUL.txt. Докладніше див . У просторах імен . "
DavidRR

Цей «чорний список Підхід» не працює на кожній системі вікон, наприклад , коли Піктограми показує вгору: en.wikipedia.org/wiki/Miscellaneous_Symbols_and_Pictographs
Січ

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

У мене не було проблем з цим кодом:

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

Наприклад, вони повернуть 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);

І це повернеться правдою:

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

0

Більш просте рішення, незалежне від ОС.

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

Використання:

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

Directory.CreateDirectory() автоматично викине у всіх наступних ситуаціях:

System.IO.IOException:
Каталог, вказаний шляхом, є файлом. -ілі- Назва мережі невідома.

System.UnauthorizedAccessException:
абонент не має необхідного дозволу.

System.ArgumentException:
шлях - це рядок нульової довжини, містить лише пробіли або містить один або кілька неприпустимих символів. Ви можете здійснити запит щодо недійсних символів за допомогою методу System.IO.Path.GetInvalidPathChars. -or- шлях має префікс або містить лише символ двокрапки (:).

System.ArgumentNullException:
шлях нульовий.

System.IO.PathTooLongException:
Вказаний шлях, ім'я файлу або обидва перевищують визначену системою максимальну довжину.

System.IO.DirectoryNotFoundException:
Вказаний шлях недійсний (наприклад, він знаходиться на невіднесеному диску).

System.NotSupportedException:
шлях містить символ двокрапки (:), який не є частиною мітки диска ("C:").

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.