Как проверить, является ли данная строка допустимым / допустимым именем файла в Windows? - PullRequest
154 голосов
/ 15 сентября 2008

Я хочу включить функцию переименования пакетного файла в моем приложении. Пользователь может ввести шаблон имени файла назначения и (после замены некоторых шаблонов в шаблоне) мне нужно проверить, будет ли это допустимое имя файла в Windows. Я пытался использовать регулярное выражение, например [a-zA-Z0-9_]+, но оно не включает много национальных символов из разных языков (например, умляуты и т. Д.) Каков наилучший способ сделать такую ​​проверку?

Ответы [ 26 ]

119 голосов
/ 15 сентября 2008

С В MSDN "Наименование файла или каталога" приведены общие соглашения о том, что такое допустимое имя файла под Windows:

Вы можете использовать любой символ в текущей кодовой странице (Unicode / ANSI выше 127), кроме:

  • < > : " / \ | ? *
  • Символы, целочисленные представления которых 0-31 (меньше ASCII-пробела)
  • Любой другой символ, который целевая файловая система не допускает (скажем, конечные периоды или пробелы)
  • Любое из имен DOS: CON, PRN, AUX, NUL, COM0, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6 , LPT7, LPT8, LPT9 (и избегайте AUX.txt и т. Д.)
  • Имя файла - все периоды

Некоторые дополнительные вещи для проверки:

  • Пути к файлам (включая имя файла) могут содержать не более 260 символов (без префикса \?\)
  • Пути к файлам Unicode (включая имя файла), содержащие более 32 000 символов при использовании \?\ (обратите внимание, что префикс может расширять компоненты каталога и приводить к переполнению лимита 32 000)
97 голосов
/ 15 сентября 2008

Список недопустимых символов можно получить из Path.GetInvalidPathChars и GetInvalidFileNameChars.

UPD: См. Предложение Стива Купера о том, как использовать их в регулярном выражении.

UPD2: Обратите внимание, что в соответствии с разделом «Примечания» в MSDN «Массив, возвращаемый этим методом, не обязательно содержит полный набор символов, недопустимых в именах файлов и каталогов». Ответ, предоставленный Sixlettervaliables , более подробно описан.

63 голосов
/ 15 сентября 2008

Для .Net Framework до 3.5 это должно работать:

Соответствие регулярных выражений поможет вам в этом. Вот фрагмент кода с использованием константы System.IO.Path.InvalidPathChars;

bool IsValidFilename(string testName)
{
    Regex containsABadCharacter = new Regex("[" 
          + Regex.Escape(System.IO.Path.InvalidPathChars) + "]");
    if (containsABadCharacter.IsMatch(testName)) { return false; };

    // other checks for UNC, drive-path format, etc

    return true;
}

Для .Net Frameworks после 3.0 это должно работать:

http://msdn.microsoft.com/en-us/library/system.io.path.getinvalidpathchars(v=vs.90).aspx

Соответствие регулярных выражений поможет вам в этом. Вот фрагмент кода с использованием константы System.IO.Path.GetInvalidPathChars();

bool IsValidFilename(string testName)
{
    Regex containsABadCharacter = new Regex("["
          + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]");
    if (containsABadCharacter.IsMatch(testName)) { return false; };

    // other checks for UNC, drive-path format, etc

    return true;
}

Как только вы это узнаете, вам также следует проверить наличие различных форматов, например, c:\my\drive и \\server\share\dir\file.ext

25 голосов
/ 15 сентября 2008

Попробуйте использовать его, и ловушка для ошибки. Разрешенный набор может меняться в разных файловых системах или в разных версиях Windows. Другими словами, если вы хотите знать, нравится ли Windows имя, передайте ему имя и дайте ему сказать.

23 голосов
/ 06 августа 2010

Этот класс очищает имена файлов и пути; используйте это как

var myCleanPath = PathSanitizer.SanitizeFilename(myBadPath, ' ');

Вот код;

/// <summary>
/// Cleans paths of invalid characters.
/// </summary>
public static class PathSanitizer
{
    /// <summary>
    /// The set of invalid filename characters, kept sorted for fast binary search
    /// </summary>
    private readonly static char[] invalidFilenameChars;
    /// <summary>
    /// The set of invalid path characters, kept sorted for fast binary search
    /// </summary>
    private readonly static char[] invalidPathChars;

    static PathSanitizer()
    {
        // set up the two arrays -- sorted once for speed.
        invalidFilenameChars = System.IO.Path.GetInvalidFileNameChars();
        invalidPathChars = System.IO.Path.GetInvalidPathChars();
        Array.Sort(invalidFilenameChars);
        Array.Sort(invalidPathChars);

    }

    /// <summary>
    /// Cleans a filename of invalid characters
    /// </summary>
    /// <param name="input">the string to clean</param>
    /// <param name="errorChar">the character which replaces bad characters</param>
    /// <returns></returns>
    public static string SanitizeFilename(string input, char errorChar)
    {
        return Sanitize(input, invalidFilenameChars, errorChar);
    }

    /// <summary>
    /// Cleans a path of invalid characters
    /// </summary>
    /// <param name="input">the string to clean</param>
    /// <param name="errorChar">the character which replaces bad characters</param>
    /// <returns></returns>
    public static string SanitizePath(string input, char errorChar)
    {
        return Sanitize(input, invalidPathChars, errorChar);
    }

    /// <summary>
    /// Cleans a string of invalid characters.
    /// </summary>
    /// <param name="input"></param>
    /// <param name="invalidChars"></param>
    /// <param name="errorChar"></param>
    /// <returns></returns>
    private static string Sanitize(string input, char[] invalidChars, char errorChar)
    {
        // null always sanitizes to null
        if (input == null) { return null; }
        StringBuilder result = new StringBuilder();
        foreach (var characterToTest in input)
        {
            // we binary search for the character in the invalid set. This should be lightning fast.
            if (Array.BinarySearch(invalidChars, characterToTest) >= 0)
            {
                // we found the character in the array of 
                result.Append(errorChar);
            }
            else
            {
                // the character was not found in invalid, so it is valid.
                result.Append(characterToTest);
            }
        }

        // we're done.
        return result.ToString();
    }

}
22 голосов
/ 15 сентября 2008

Вот что я использую:

    public static bool IsValidFileName(this string expression, bool platformIndependent)
    {
        string sPattern = @"^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\"";|/]+$";
        if (platformIndependent)
        {
           sPattern = @"^(([a-zA-Z]:|\\)\\)?(((\.)|(\.\.)|([^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?))\\)*[^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?$";
        }
        return (Regex.IsMatch(expression, sPattern, RegexOptions.CultureInvariant));
    }

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

18 голосов
/ 19 сентября 2008

Нужно помнить один угловой случай, который удивил меня, когда я впервые узнал об этом: Windows позволяет вводить пробелы в именах файлов! Например, ниже приведены все допустимые и разные имена файлов в Windows (за исключением кавычек):

"file.txt"
" file.txt"
"  file.txt"

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

9 голосов
/ 04 марта 2017

Упрощение ответа Евгения Каца:

bool IsFileNameCorrect(string fileName){
    return !fileName.Any(f=>Path.GetInvalidFileNameChars().Contains(f))
}

Или

bool IsFileNameCorrect(string fileName){
    return fileName.All(f=>!Path.GetInvalidFileNameChars().Contains(f))
}
8 голосов
/ 15 сентября 2008

Microsoft Windows: ядро ​​Windows запрещает использование символов в диапазоне 1-31 (т. Е. 0x01-0x1F) и символов "*: <>? \ |. Хотя NTFS позволяет каждому компоненту пути (каталогу или имени файла) быть 255 длиной символов и длиной до 32767 символов, ядро ​​Windows поддерживает только пути длиной до 259. Кроме того, Windows запрещает использование имен устройств MS-DOS AUX, CLOCK $, COM1, COM2, COM3, COM4, ​​COM5 , COM6, COM7, COM8, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, NUL и PRN, а также эти имена с любым расширением (например, AUX.txt), кроме случаев использования длинных путей UNC (например, \. \ C: \ nul.txt или \? \ D: \ aux \ con). (На самом деле, CLOCK $ может использоваться, если предоставляется расширение.) Эти ограничения применяются только в Windows - Linux, например, позволяет использовать "*: <>? \ | даже в NTFS.

Источник: http://en.wikipedia.org/wiki/Filename

7 голосов
/ 15 сентября 2008

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

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