Проверьте, является ли строка допустимым путем к каталогу (папке) Windows


84

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

В моем приложении папка представляет собой место установки. При условии , что путь к папке является действительным, я хочу , чтобы определить , является ли папка существует, и создать его , если он не делает.

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

В моем поиске в Google я нашел предложение использовать регулярное выражение для проверки правильности формата. У меня нет опыта работы с регулярными выражениями, и мне интересно, насколько это жизнеспособный подход. Вот что я нашел:

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, но поскольку мне нужна возможность создания папки на месте, я не могу просто пойти на это.
Pudpuduk

@Robert По второй теме, которую вы связали - ввод одного слова все равно пройдет проверку, указанную в ответах на этот вопрос.
Pudpuduk

Ответы:


119

Звоните Path.GetFullPath; он выдаст исключения, если путь недействителен.

Чтобы запретить относительные пути (например, Word ), вызовите Path.IsPathRooted.


Я знал, что есть что-то попроще! И спасибо, я не подумал о проблеме относительности путей.
Pudpuduk

3
Спасибо SLaks. Я видел много дубликатов и выполнял много поисков в Google (более одного раза), но впервые вижу хороший ответ на этот конкретный вопрос.
Роберт Харви

5
Path.GetFullPath ("con.txt") - допустимое имя файла.
Christoffer

8
@Slaks Это слишком старо, чтобы оставлять комментарии, но я все же хочу оставить здесь один по той причине, что я дал вам свой голос -1. Path.GetFullPath (), похоже, работает нормально, но что, если путь: «Z: \\\\\\\\ Hi \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\= (...) выдает результат: Z: \ Hi \ Там, и исключения не возникает. Мне пришлось немного изменить его, сравнив строку, возвращаемую GetFullPath (), и исходную строку следующим образом: private bool IsPathValid (string path) {try {string fullPath = Path.GetFullPath (path); вернуть fullPath == путь; } catch {return false;}}
King King

4
@KingKing Из этого ответа Linux на unix.stackexchange.com: «Множественные косые черты разрешены и эквивалентны одной косой черте ..» Я наблюдал то же самое в Windows (хотя ведущие косые черты в пути UNC могут обрабатываться по-другому). Для доказательства этого, в командной строке, попробуйте следующее: cd C:\\\\\\\Windows\\\\\\\System32. Что касается Windows, я не могу найти авторитетный источник, документирующий это поведение, но, конечно, приветствовал бы указатель на него.
DavidRR

19

Я вообще не согласен с SLaks. Это решение не сработало для меня. Исключение произошло не так, как ожидалось. Но этот код работал у меня:

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

63
Действительный путь не обязательно является существующим каталогом ... это именно та проблема, о которой здесь спрашивают,
Бенлитц

2
вопрос был связан с проверкой строки пути, путь, который мог не существовать.
Мубашар 02

Я считаю, что это правильный способ. Исключений ожидать не следует. Этот метод также проверяет неправильные символы в указанном пути.
Евгений Максимов

Это условие само вызовет исключение, если «путь» не является реальным путем, поскольку Directory.Exists требует действительного пути.
M. Fawad Surosh

Совершенно неправильный ответ! Интересно, как он получил 32 положительных голоса (на данный момент). Должно быть, люди, которые смотрели не в том месте из-за проблемы, с которой они столкнулись, и наткнулись на это.
Sнаđошƒаӽ

13

Path.GetFullPath дает только исключения ниже

Путь ArgumentException - это строка нулевой длины, содержащая только пробелы или один или несколько недопустимых символов, определенных в GetInvalidPathChars. -или- Системе не удалось получить абсолютный путь.

SecurityException У вызывающего абонента нет необходимых разрешений.

Путь ArgumentNullException равен нулю.

Путь 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

Этот "черный список" работает не во всех системах Windows, например, когда появляются пиктограммы: 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);

3

Более простое независимое от ОС решение:

Продолжайте и попробуйте создать фактический каталог; если есть проблема или имя недействительно, ОС автоматически пожалуется, и код выдаст.

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. -или- путь имеет префикс или содержит только двоеточие (:).

System.ArgumentNullException:
путь равен нулю.

System.IO.PathTooLongException:
указанный путь, имя файла или оба параметра превышают максимальную длину, определенную системой.

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

System.NotSupportedException:
путь содержит символ двоеточия (:), который не является частью метки диска («C:»).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.