Какие символы запрещены в именах каталогов Windows и Linux?

Я знаю, что / является незаконным в Linux, и следующие недопустимы в Windows (я думаю) *."/\[]:;|=,

Что еще мне не хватает?

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

Мне нужно сначала создать каталог в файловой системе, используя имя, которое может содержать запрещенные символы, поэтому я планирую заменить эти символы подчеркиванием. Затем мне нужно записать этот каталог и его содержимое в zip-файл (с использованием Java), поэтому любые дополнительные советы, касающиеся имен zip-каталогов, будут оценены.

20 ответов

Решение

"Полное руководство" по запрещенным символам имени файла не будет работать в Windows, поскольку оно резервирует имена файлов и символы. Да, такие персонажи*"? и другие запрещены, но существует бесконечное количество имен, состоящих только из допустимых символов, которые запрещены. Например, пробелы и точки являются допустимыми символами имени файла, но имена, состоящие только из этих символов, запрещены.

Windows не различает прописные и строчные буквы, поэтому вы не можете создать папку с именем A если кто-то назвал a уже существует. Хуже, казалось бы, разрешенные имена, такие как PRN а также CONи многие другие зарезервированы и не допускаются. Windows также имеет несколько ограничений по длине; имя файла, допустимое в одной папке, может стать недействительным при перемещении в другую папку. Правила именования файлов и папок указаны в MSDN.

Как правило, вы не можете использовать сгенерированный пользователем текст для создания имен каталогов Windows. Если вы хотите, чтобы пользователи могли называть все, что они хотят, вы должны создать безопасные имена, такие как A, AB, A2 и др. сохраняйте сгенерированные пользователем имена и их пути в файле данных приложения и выполняйте сопоставление путей в своем приложении.

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

Давайте будем простыми и сначала ответим на вопрос.

  1. Запрещенные печатные символы ASCII:

    • Linux/Unix:

      / (forward slash)
      
    • Окна:

      < (less than)
      > (greater than)
      : (colon - sometimes works, but is actually NTFS Alternate Data Streams)
      " (double quote)
      / (forward slash)
      \ (backslash)
      | (vertical bar or pipe)
      ? (question mark)
      * (asterisk)
      
  2. Непечатные символы

    Если ваши данные поступают из источника, который разрешает непечатные символы, есть еще что проверить.

    • Linux/Unix:

      0 (NULL byte)
      
    • Окна:

      0-31 (ASCII control characters)
      

    Примечание. Хотя в файловых системах Linux/Unix разрешено создавать файлы с управляющими символами в имени файла, пользователям может показаться кошмаром иметь дело с такими файлами.

  3. Зарезервированные имена файлов

    Следующие имена файлов зарезервированы:

    • Окна:

      CON, PRN, AUX, NUL 
      COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
      LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9
      

      (как самостоятельно, так и с произвольным расширением файла, например LPT1.txt).

  4. Другие правила

    • Окна:

      Имена файлов не могут заканчиваться пробелом или точкой.

В Linux и других Unix-системах есть только два символа, которые не могут появляться в имени файла или каталога, и это NUL '\0' и косая черта '/', Разумеется, косая черта может появляться в имени пути, разделяющем компоненты каталога.

Ходят слухи, что у Стивена Борна (известной "оболочки") был каталог, содержащий 254 файла, по одному на каждую букву (код символа), которая может появиться в имени файла (исключая/,'\0'; имя .был текущий каталог, конечно). Он использовался для тестирования оболочки Bourne и регулярно наносил ущерб неосторожным программам, таким как программы резервного копирования.

Другие люди рассмотрели правила Windows.

Обратите внимание, что MacOS X имеет регистронезависимую файловую систему.


1 Керниган и Пайк из "Практики программирования" так и сказали в главе 6 "Тестирование", §6.5 Стресс-тесты:

Когда Стив Борн писал свою оболочку Unix (известную как оболочка Борна), он создал каталог из 254 файлов с односимвольными именами, по одному на каждое значение байта, кроме '\0' и косая черта, два символа, которые не могут появляться в именах файлов Unix. Он использовал этот каталог для всевозможных тестов сопоставления с образцом и токенизации. (Тестовый каталог, конечно, был создан программой.) В течение многих лет этот каталог был проклятием программ для обхода файловых деревьев; это проверило их на разрушение.

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

Это не решает проблему зарезервированных имен в целевой файловой системе, но с белым списком легче снизить риски в источнике.

В этом духе это ряд символов, которые можно считать безопасными:

  • Буквы (az AZ) - также символы Юникода, если необходимо
  • Цифры (0-9)
  • Нижнее подчеркивание (_)
  • Дефис (-)
  • Космос
  • Точка (.)

И любые дополнительные безопасные символы, которые вы хотите разрешить. Помимо этого, вам просто нужно применить некоторые дополнительные правила, касающиеся пробелов и точек. Обычно этого достаточно:

  • Имя должно содержать хотя бы одну букву или цифру (чтобы избежать только точек / пробелов)
  • Имя должно начинаться с буквы или цифры (чтобы избежать начальных точек / пробелов)

Это уже позволяет довольно сложные и бессмысленные имена. Например, эти имена будут возможны с этими правилами и будут действительными именами файлов в Windows/Linux:

  • A...........ext
  • B -.- .ext

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

Самый простой способ получить ответ от Windows - это попытаться переименовать файл через Проводник и ввести / для нового имени. Windows выдаст сообщение о недопустимых символах.

A filename cannot contain any of the following characters:
    \ / : * ? " < > | 

https://support.microsoft.com/en-us/kb/177506

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

Если вы хотите написать переносную функцию для проверки ввода пользователя и создания имен файлов на основе этого, краткий ответ - нет. Взгляните на портативный модуль, такой как Perl File::Spec, чтобы увидеть все прыжки, необходимые для выполнения такой "простой" задачи.

Проблемы с определением того, что законно, а что нет, уже были рассмотрены, и были предложены белые списки. Но Windows поддерживает более 8-битные символы. Википедия утверждает, что (например)

буква-модификатор двоеточие [(см. 7. ниже)] иногда используется в именах файлов Windows, поскольку оно идентично двоеточию в шрифте пользовательского интерфейса Segoe, используемом для имен файлов. Само двоеточие [унаследованный ASCII] не допускается.

Поэтому я хочу представить гораздо более либеральный подход с использованием символов Unicode для замены "незаконных". Я нашел результат в моем сопоставимом варианте использования гораздо более читаемым. Взгляните, например, в этот блок. Кроме того, вы даже можете восстановить исходный контент из этого. Возможные варианты и исследования представлены в следующем списке:

  1. Вместо *(U+002A * ASTERISK), вы можете использовать один из множества перечисленных, напримерU+2217 ∗ (ASTERISK OPERATOR) или Full Width Asterisk U+FF0A *
  2. Вместо этого . вы можете использовать один из них, например⋅ U+22C5 dot operator
  3. Вместо этого " вы можете использовать“ U+201C english leftdoublequotemark(Альтернативы см. Здесь)
  4. Вместо /(/ SOLIDUS U+002F), ты можешь использовать ∕ DIVISION SLASH U+2215(другие здесь)
  5. Вместо \(\ U+005C Reverse solidus), ты можешь использовать ⧵ U+29F5 Reverse solidus operator( больше)
  6. Вместо [(U+005B Left square bracket) и ](U+005D Right square bracket), вы можете использовать, например, U+FF3B[ FULLWIDTH LEFT SQUARE BRACKET а также U+FF3D ]FULLWIDTH RIGHT SQUARE BRACKET(от здесь, больше возможностей здесь)
  7. Вместо этого : вы можете использоватьU+2236 ∶ RATIO (for mathematical usage) или U+A789 ꞉ MODIFIER LETTER COLON, (см. двоеточие (буква), которое иногда используется в именах файлов Windows, поскольку оно идентично двоеточию в шрифте пользовательского интерфейса Segoe, используемом для имен файлов. Само двоеточие не допускается) (см. здесь)
  8. Вместо этого ; вы можете использоватьU+037E ; GREEK QUESTION MARK(см. здесь)
  9. Для |, есть некоторые хорошие заменители, такие как:U+0964 । DEVANAGARI DANDA, U+2223 ∣ DIVIDES или U+01C0 ǀ LATIN LETTER DENTAL CLICK( Википедия). Также символы рисования прямоугольников содержат различные другие параметры.
  10. Вместо ,(, U+002C COMMA), вы можете использовать, например, ‚ U+201A SINGLE LOW-9 QUOTATION MARK(см. здесь)
  11. Для ?(U+003F ? QUESTION MARK), это хорошие кандидаты: U+FF1F ? FULLWIDTH QUESTION MARK или U+FE56 ﹖ SMALL QUESTION MARK(от него снова, еще два из Дингбаты блока, поиск "вопрос")

Для Windows вы можете проверить это с помощью PowerShell

$PathInvalidChars = [System.IO.Path]::GetInvalidPathChars() #36 chars

Для отображения кодов UTF-8 вы можете конвертировать

$enc = [system.Text.Encoding]::UTF8
$PathInvalidChars | foreach { $enc.GetBytes($_) }

$FileNameInvalidChars = [System.IO.Path]::GetInvalidFileNameChars() #41 chars

$FileOnlyInvalidChars = @(':', '*', '?', '\', '/') #5 chars - as a difference

Для тех, кто ищет регулярное выражение:

const BLACKLIST = /[<>:"\/\\|?*]/g;

В Windows 10 (2019) следующие символы запрещены из-за ошибки при попытке их ввода:

Имя файла не может содержать ни один из следующих символов:

\ / : * ? " < > |

.NET Framework System.IO предоставляет следующие функции для недопустимых символов файловой системы:

Эти функции должны возвращать соответствующие результаты в зависимости от платформы, на которой работает среда выполнения.NET.

Вот реализация С # для окон на основе ответа Кристофера Озбека

Он был усложнен логическим значением containsFolder, но, надеюсь, охватывает все

/// <summary>
/// This will replace invalid chars with underscores, there are also some reserved words that it adds underscore to
/// </summary>
/// <remarks>
/// https://stackru.com/questions/1976007/what-characters-are-forbidden-in-windows-and-linux-directory-names
/// </remarks>
/// <param name="containsFolder">Pass in true if filename represents a folder\file (passing true will allow slash)</param>
public static string EscapeFilename_Windows(string filename, bool containsFolder = false)
{
    StringBuilder builder = new StringBuilder(filename.Length + 12);

    int index = 0;

    // Allow colon if it's part of the drive letter
    if (containsFolder)
    {
        Match match = Regex.Match(filename, @"^\s*[A-Z]:\\", RegexOptions.IgnoreCase);
        if (match.Success)
        {
            builder.Append(match.Value);
            index = match.Length;
        }
    }

    // Character substitutions
    for (int cntr = index; cntr < filename.Length; cntr++)
    {
        char c = filename[cntr];

        switch (c)
        {
            case '\u0000':
            case '\u0001':
            case '\u0002':
            case '\u0003':
            case '\u0004':
            case '\u0005':
            case '\u0006':
            case '\u0007':
            case '\u0008':
            case '\u0009':
            case '\u000A':
            case '\u000B':
            case '\u000C':
            case '\u000D':
            case '\u000E':
            case '\u000F':
            case '\u0010':
            case '\u0011':
            case '\u0012':
            case '\u0013':
            case '\u0014':
            case '\u0015':
            case '\u0016':
            case '\u0017':
            case '\u0018':
            case '\u0019':
            case '\u001A':
            case '\u001B':
            case '\u001C':
            case '\u001D':
            case '\u001E':
            case '\u001F':

            case '<':
            case '>':
            case ':':
            case '"':
            case '/':
            case '|':
            case '?':
            case '*':
                builder.Append('_');
                break;

            case '\\':
                builder.Append(containsFolder ? c : '_');
                break;

            default:
                builder.Append(c);
                break;
        }
    }

    string built = builder.ToString();

    if (built == "")
    {
        return "_";
    }

    if (built.EndsWith(" ") || built.EndsWith("."))
    {
        built = built.Substring(0, built.Length - 1) + "_";
    }

    // These are reserved names, in either the folder or file name, but they are fine if following a dot
    // CON, PRN, AUX, NUL, COM0 .. COM9, LPT0 .. LPT9
    builder = new StringBuilder(built.Length + 12);
    index = 0;
    foreach (Match match in Regex.Matches(built, @"(^|\\)\s*(?<bad>CON|PRN|AUX|NUL|COM\d|LPT\d)\s*(\.|\\|$)", RegexOptions.IgnoreCase))
    {
        Group group = match.Groups["bad"];
        if (group.Index > index)
        {
            builder.Append(built.Substring(index, match.Index - index + 1));
        }

        builder.Append(group.Value);
        builder.Append("_");        // putting an underscore after this keyword is enough to make it acceptable

        index = group.Index + group.Length;
    }

    if (index == 0)
    {
        return built;
    }

    if (index < built.Length - 1)
    {
        builder.Append(built.Substring(index));
    }

    return builder.ToString();
}

Я всегда предполагал, что запрещенные символы в именах файлов Windows означают, что все экзотические символы также будут запрещены. Меня особенно раздражала невозможность использовать?, / И:. Однажды я обнаружил, что фактически запрещены только те символы. Могут использоваться другие символы Юникода. Таким образом, были идентифицированы ближайшие символы Unicode к запрещенным, которые я смог найти, и для них были созданы макросы MS Word как Alt- ?, Alt-: и т.д. Имя файла Windows. Пока проблем не было.

Вот заменяющие символы (Alt - десятичный Unicode):

⃰ Alt-8432
⁄ Alt-8260
⃥ Alt-8421
∣ Alt-
8739ⵦ Alt-11622⮚ Alt-11162‽
Alt-8253፡ Alt 4961‶ Alt-8246″ Alt-8243

В качестве теста я сформировал имя файла, используя все эти символы, и Windows приняла его.

Хотя единственные нелегальные символы Unix могут быть / а также NULL, хотя некоторые соображения для интерпретации командной строки должны быть включены.

Например, хотя это может быть законным, чтобы назвать файл 1>&2 или же 2>&1 в Unix такие имена файлов могут быть неверно истолкованы при использовании в командной строке.

Точно так же можно было бы назвать файл $PATH, но при попытке доступа к нему из командной строки оболочка будет переводить $PATH к его значению переменной.

По состоянию на 18/04/2017 среди простых ответов на эту тему нет простого черного или белого списка символов и имен файлов - и ответов много.

Лучшее предложение, которое я мог придумать, состояло в том, чтобы позволить пользователю называть файл так, как ему нравится. Используя обработчик ошибок, когда приложение пытается сохранить файл, перехватить любые исключения, предположить, что виновато имя файла (очевидно, после того, как убедитесь, что путь сохранения тоже был в порядке), и запросить у пользователя новое имя файла. Для достижения наилучших результатов поместите эту процедуру проверки в цикл, который продолжается до тех пор, пока пользователь не поймет это правильно или не сдастся. Лучше всего сработало для меня (по крайней мере, в VBA).

Например, на вопрос ОП уже был дан полный ответ здесь и здесь .Здесь я просто расширяю эти ответы, показывая, как это исправить в Linux:

В Linux найдите все имена файлов и папок, содержащие символы, запрещенные в Windows.

Если вы используете Linux и просто хотите найти все имена файлов и папок, содержащие символы, запрещенные в Windows, вы можете запустить следующую команду:

      # Find all files and folders with any of these Windows-illegal characters in
# their name:  \ : * ? " < > |
find . -name '*[\\:\*?\"<\>|]*'

Например, это действительно полезно, так как вы можете вручную очистить или «исправить» репозиторий кода git, написанный в Linux, который теперь вам нужно клонировать и использовать в Windows. Если вы сначала не найдете, не очистите и не исправите все несовместимые с Windows символы в именах файлов и папок, репозиторий не сможет клонировать в Windows, и вы увидите такие ошибки, например:

      $ git clone https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world.git
Cloning into 'eRCaGuy_hello_world'...
remote: Enumerating objects: 4342, done.
remote: Counting objects: 100% (1184/1184), done.
remote: Compressing objects: 100% (366/366), done.
remote: Total 4342 (delta 819), reused 1149 (delta 799), pack-reused 3158Receiving objects: 100% (4342/4342), 6.50 Mi
Receiving objects: 100% (4342/4342), 7.02 MiB | 6.50 MiB/s, done.

Resolving deltas: 100% (2725/2725), done.
error: invalid path 'cpp/class_copy_constructor_and_assignment_operator/Link to Copy constructor vs assignment operat
or in C++ - GeeksforGeeks%%%%% [see `t2 = t1;  -- calls assignment operator, same as "t2.operator=(t1);" `].desktop'
fatal: unable to checkout working tree
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry with 'git restore --source=HEAD :/'

Выше вы можете увидетьerror: invalid pathчто привело к сбою, потому что мое имя файла по путиcpp/class_copy_constructor_and_assignment_operator/Link to Copy constructor vs assignment operat or in C++ - GeeksforGeeks%%%%% [see `t2 = t1; -- calls assignment operator, same as "t2.operator=(t1);" `].desktopнедействителен в Windows, что приводит к невозможности клонирования репозитория в Windows, поскольку в нем есть символ двойной кавычки (). Итак, я собираюсь вручную переименовать этот файл в Linux, удалив символы, и отправить изменения в свой репозиторий git, чтобы затем клонировать его в Windows.

Сохраняйте пути к файлам Windows <= 259 символов и пути к папкам <= 248 символов (ошибка:)

Даже если вы удалите запрещенные символы из своей папки и имен файлов, найдя их с помощьюfind . -name '*[\\:\*?\"<\>|]*'приведенную выше команду, имейте в виду, что WindowsMAX_PATHограничение по-прежнему действует: общая длина пути ограничивается <= 259 символами для файла или <= 248 символами для папки. См. здесь: Максимальная длина имени файла в NTFS (Windows XP и Windows Vista)?

Если вы нарушите это ограничение пути, а затем попытаетесьgit cloneрепозиторий в Windows, вы получите этоFilename too longошибка:

      $ git clone https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world.git
Cloning into 'eRCaGuy_hello_world'...
remote: Enumerating objects: 4347, done.
remote: Counting objects: 100% (1189/1189), done.
remote: Compressing objects: 100% (370/370), done.
remote: Total 4347 (delta 823), reused 1152 (delta 800), pack-reused 3158
Receiving objects: 100% (4347/4347), 7.03 MiB | 5.82 MiB/s, done.
Resolving deltas: 100% (2729/2729), done.
error: unable to create file cpp/class_copy_constructor_and_assignment_operator/Link to Copy constructor vs assignmen
t operator in C++ - GeeksforGeeks%%%%% [see `t2 = t1;  -- calls assignment operator, same as ''t2.operator=(t1);'' `]
.desktop: Filename too long
Updating files: 100% (596/596), done.
Filtering content: 100% (8/8), 2.30 MiB | 2.21 MiB/s, done.
fatal: unable to checkout working tree
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry with 'git restore --source=HEAD :/'

Обратите внимание на эту часть из-за моего смехотворно длинного имени файла:

error: unable to create file cpp/class_copy_constructor_and_assignment_operator/Link to Copy constructor vs assignment operator in C++ - GeeksforGeeks%%%%% [see `t2 = t1; -- calls assignment operator, same as ''t2.operator=(t1);'' `].desktop: Filename too long

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

Использованная литература:

  1. В Windows 10 Pro я пытался ввести"в имя папки, и я получил всплывающее окно с ошибкой:

  2. Я использовал https://regex101.com/ (см.: https://regex101.com/r/lI5Lg9/1), чтобы построить и протестировать[\\:\*?\"<\>|]регулярное выражение, чтобы узнать, какие символы следует экранировать, просмотрев раздел «Объяснение» справа:

Для меня этого достаточно:

      def escape_filename(name):
    """
    Replace invalid characters on Linux/Windows/MacOS with underscores.
    >>> escape_filename("COM10.")  # Should be allowed, but not "COM1" or "COM1.anything" on Windows according to https://stackoverflow.com/a/31976060/819417
    '_0_'
    """
    return re.sub(r'[/\\<>:"|?*\0-\31]|^(AUX|COM[1-9]|CON|LPT[1-9]|NUL|PRN)|[ .]$', "_", name, flags=re.IGNORECASE)

В оболочках Unix вы можете заключить почти каждый символ в одинарные кавычки ', За исключением самой одиночной кавычки, и вы не можете выразить управляющие символы, потому что \ не расширен. Доступ к самой одиночной кавычке из строки в кавычках возможен, потому что вы можете объединять строки с одинарными и двойными кавычками, например 'I'"'"'m' который может быть использован для доступа к файлу с именем "I'm" (здесь также возможна двойная кавычка).

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

Если вы хотите быть милым, не используйте какие-либо символы, которые оболочка и типичные команды используют в качестве синтаксических элементов, иногда зависящих от позиции, например, вы все еще можете использовать -, но не как первый персонаж; то же самое с ., вы можете использовать его в качестве первого символа только тогда, когда вы имеете в виду ("скрытый файл"). Когда вы имеете в виду, ваши имена файлов являются escape-последовательностями VT100;-), так что ls искажает вывод.

При создании ярлыков Интернета в Windows для создания имени файла пропускаются недопустимые символы, кроме косой черты, которая преобразуется в минус.

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

$CharactersInvalidForFileName = {
    "pound" -> "#",
    "left angle bracket" -> "<",
    "dollar sign" -> "$",
    "plus sign" -> "+",
    "percent" -> "%",
    "right angle bracket" -> ">",
    "exclamation point" -> "!",
    "backtick" -> "`",
    "ampersand" -> "&",
    "asterisk" -> "*",
    "single quotes" -> "“",
    "pipe" -> "|",
    "left bracket" -> "{",
    "question mark" -> "?",
    "double quotes" -> "”",
    "equal sign" -> "=",
    "right bracket" -> "}",
    "forward slash" -> "/",
    "colon" -> ":",
    "back slash" -> "\\",
    "lank spaces" -> "b",
    "at sign" -> "@"
};
Другие вопросы по тегам