Подтвердить что ты не робот

.Net: Как проверить незаконные символы в пути?

Есть ли способ проверить, имеет ли строка, предназначенную для пути, недопустимые символы, в .Net? Я знаю, что могу перебирать каждый символ в Path.InvalidPathChars, чтобы увидеть, содержит ли моя String один, но я бы предпочел простое, возможно, более формальное решение.

Есть ли один?

Я обнаружил, что все еще получаю исключение, если я только проверяю Get

Update:

Я обнаружил, что GetInvalidPathChars не охватывает все недопустимые символы пути. У GetInvalidFileNameChars есть еще 5, включая '?', С которыми я столкнулся. Я собираюсь переключиться на это, и я отчитаю, если это тоже окажется неадекватным.

Обновление 2:

GetInvalidFileNameChars определенно не то, что я хочу. Он содержит ':', который будет содержать любой абсолютный путь ( "C:\whatever" ). Я думаю, что мне просто придется использовать GetInvalidPathChars в конце концов и добавить в '?' и любые другие персонажи, которые вызывают у меня проблемы по мере их появления. Приветствуем лучшие решения.

4b9b3361

Ответ 1

InvalidPathChars устарел. Вместо этого используйте GetInvalidPathChars():

    public static bool FilePathHasInvalidChars(string path)
    {

        return (!string.IsNullOrEmpty(path) && path.IndexOfAny(System.IO.Path.GetInvalidPathChars()) >= 0);
    }

Редактирование: немного длиннее, но обрабатывает путь и файл недопустимыми символами в одной функции:

    // WARNING: Not tested
    public static bool FilePathHasInvalidChars(string path)
    {
        bool ret = false;
        if(!string.IsNullOrEmpty(path))
        {
            try
            {
                // Careful!
                //    Path.GetDirectoryName("C:\Directory\SubDirectory")
                //    returns "C:\Directory", which may not be what you want in
                //    this case. You may need to explicitly add a trailing \
                //    if path is a directory and not a file path. As written, 
                //    this function just assumes path is a file path.
                string fileName = System.IO.Path.GetFileName(path);
                string fileDirectory = System.IO.Path.GetDirectoryName(path);

                // we don't need to do anything else,
                                    // if we got here without throwing an 
                                    // exception, then the path does not
                                    // contain invalid characters
            }
            catch (ArgumentException)
            {
                                    // Path functions will throw this 
                                    // if path contains invalid chars
                ret = true;
            }
        }
        return ret;
    }

Ответ 2

Будьте осторожны, полагаясь на Path.GetInvalidFileNameChars, который может быть не таким надежным, как вы думаете. Обратите внимание на следующее примечание в документации MSDN по Path.GetInvalidFileNameChars:

Массив, возвращаемый с помощью этого метода, не гарантированно содержит полный набор символов, которые недействительны в именах файлов и каталогов. Полный набор недопустимых символов может отличаться в зависимости от файловой системы. Например, на платформах для настольных компьютеров Windows недопустимые символы пути могут включать символы ASCII/Unicode с 1 по 31, а также цитату ("), меньше (<), больше ( > ), pipe (|), backspace (\ b), null (\ 0) и tab (\ t).

Это не лучше с Path.GetInvalidPathChars. Он содержит то же самое замечание.

Ответ 3

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

Вот что я в конечном итоге использовал в 3 этапа:

Шаг 1: Пользовательская очистка.

 
public static string RemoveSpecialCharactersUsingCustomMethod(this string expression, bool removeSpecialLettersHavingASign = true)
{
    var newCharacterWithSpace = " ";
    var newCharacter = "";

    // Return carriage handling
    // ASCII LINE-FEED character (LF),
    expression = expression.Replace("\n", newCharacterWithSpace);
    // ASCII CARRIAGE-RETURN character (CR) 
    expression = expression.Replace("\r", newCharacterWithSpace);

    // less than : used to redirect input, allowed in Unix filenames, see Note 1
    expression = expression.Replace(@"<", newCharacter);
    // greater than : used to redirect output, allowed in Unix filenames, see Note 1
    expression = expression.Replace(@">", newCharacter);
    // colon: used to determine the mount point / drive on Windows; 
    // used to determine the virtual device or physical device such as a drive on AmigaOS, RT-11 and VMS; 
    // used as a pathname separator in classic Mac OS. Doubled after a name on VMS, 
    // indicates the DECnet nodename (equivalent to a NetBIOS (Windows networking) hostname preceded by "\\".). 
    // Colon is also used in Windows to separate an alternative data stream from the main file.
    expression = expression.Replace(@":", newCharacter);
    // quote : used to mark beginning and end of filenames containing spaces in Windows, see Note 1
    expression = expression.Replace(@"""", newCharacter);
    // slash : used as a path name component separator in Unix-like, Windows, and Amiga systems. 
    // (The MS-DOS command.com shell would consume it as a switch character, but Windows itself always accepts it as a separator.[16][vague])
    expression = expression.Replace(@"/", newCharacter);
    // backslash : Also used as a path name component separator in MS-DOS, OS/2 and Windows (where there are few differences between slash and backslash); allowed in Unix filenames, see Note 1
    expression = expression.Replace(@"\", newCharacter);
    // vertical bar or pipe : designates software pipelining in Unix and Windows; allowed in Unix filenames, see Note 1
    expression = expression.Replace(@"|", newCharacter);
    // question mark : used as a wildcard in Unix, Windows and AmigaOS; marks a single character. Allowed in Unix filenames, see Note 1
    expression = expression.Replace(@"?", newCharacter);
    expression = expression.Replace(@"!", newCharacter);
    // asterisk or star : used as a wildcard in Unix, MS-DOS, RT-11, VMS and Windows. Marks any sequence of characters 
    // (Unix, Windows, later versions of MS-DOS) or any sequence of characters in either the basename or extension 
    // (thus "*.*" in early versions of MS-DOS means "all files". Allowed in Unix filenames, see note 1
    expression = expression.Replace(@"*", newCharacter);
    // percent : used as a wildcard in RT-11; marks a single character.
    expression = expression.Replace(@"%", newCharacter);
    // period or dot : allowed but the last occurrence will be interpreted to be the extension separator in VMS, MS-DOS and Windows. 
    // In other OSes, usually considered as part of the filename, and more than one period (full stop) may be allowed. 
    // In Unix, a leading period means the file or folder is normally hidden.
    expression = expression.Replace(@".", newCharacter);
    // space : allowed (apart MS-DOS) but the space is also used as a parameter separator in command line applications. 
    // This can be solved by quoting, but typing quotes around the name every time is inconvenient.
    //expression = expression.Replace(@"%", " ");
    expression = expression.Replace(@"  ", newCharacter);

    if (removeSpecialLettersHavingASign)
    {
        // Because then issues to zip
        // More at : http://www.thesauruslex.com/typo/eng/enghtml.htm
        expression = expression.Replace(@"ê", "e");
        expression = expression.Replace(@"ë", "e");
        expression = expression.Replace(@"ï", "i");
        expression = expression.Replace(@"œ", "oe");
    }

    return expression;
}

Шаг 2. Проверьте все недопустимые символы, которые еще не удалены.

A дополнительный этап проверки, я использую метод Path.GetInvalidPathChars(), указанный выше, для обнаружения любых возможных недопустимых символов, которые еще не удалены.

public static bool ContainsAnyInvalidCharacters(this string path)
{
    return (!string.IsNullOrEmpty(path) && path.IndexOfAny(Path.GetInvalidPathChars()) >= 0);
}

Шаг 3. Очистите любые специальные символы, обнаруженные на шаге 2.

И, наконец, я использую этот метод как последний шаг, чтобы очистить все, что осталось.  (from Как удалить недопустимые символы из пути и имени файла?):

public static string RemoveSpecialCharactersUsingFrameworkMethod(this string path)
{
    return Path.GetInvalidFileNameChars().Aggregate(path, (current, c) => current.Replace(c.ToString(), string.Empty));
}

Я регистрирую любой недопустимый символ, не очищенный на первом шаге. Я решил пойти таким путем, чтобы улучшить свой пользовательский метод, как только обнаружена "утечка". Я не могу полагаться на Path.GetInvalidFileNameChars() из-за следующего вышеприведенного оператора (из MSDN):

"Массив, возвращенный из этого метода, не гарантированно содержит полный набор символов, недопустимых в файле и каталоге имена."

Это может быть не идеальное решение, но, учитывая контекст моего приложения и требуемый уровень надежности, это лучшее решение, которое я нашел.

Ответ 4

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

/// <summary>Determines if the path contains invalid characters.</summary>
/// <remarks>This method is intended to prevent ArgumentException from being thrown when creating a new FileInfo on a file path with invalid characters.</remarks>
/// <param name="filePath">File path.</param>
/// <returns>True if file path contains invalid characters.</returns>
private static bool ContainsInvalidPathCharacters(string filePath)
{
    for (var i = 0; i < filePath.Length; i++)
    {
        int c = filePath[i];

        if (c == '\"' || c == '<' || c == '>' || c == '|' || c == '*' || c == '?' || c < 32)
            return true;
    }

    return false;
}

Затем я использовал его так же, как и его завершение в блок try/catch для безопасности:

if ( !string.IsNullOrWhiteSpace(path) && !ContainsInvalidPathCharacters(path))
{
    FileInfo fileInfo = null;

    try
    {
        fileInfo = new FileInfo(path);
    }
    catch (ArgumentException)
    {            
    }

    ...
}