Почему в Windows существует ограничение длины пути в 260 символов?
Я сталкивался с этой проблемой несколько раз в неподходящие моменты:
- пытаясь работать над проектами Java с открытым исходным кодом с глубокими путями
- Хранение глубоких вики-деревьев Fitnesse в системе контроля версий
- Ошибка при попытке использовать Bazaar для импорта моего дерева управления исходным кодом
Почему этот предел существует?
Почему это еще не было удалено?
Как вы справляетесь с ограничением пути? ... и нет, переход на Linux или Mac OS X не является правильным ответом на этот вопрос;)
12 ответов
Цитировать эту статью http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
Ограничение максимальной длины пути
В Windows API (с некоторыми исключениями, обсуждаемыми в следующих параграфах), максимальная длина пути равна MAX_PATH, которая определяется как 260 символов. Локальный путь структурирован в следующем порядке: буква диска, двоеточие, обратная косая черта, компоненты имен, разделенные обратной косой чертой, и завершающий нулевой символ. Например, максимальный путь на диске D равен "D: \some 256-символьная строка пути
", где " " представляет невидимый завершающий нулевой символ для текущей системной кодовой страницы. (Символы < > используются здесь для наглядности и не могут быть частью допустимой строки пути.)
Теперь мы видим, что это 1+2+256+1 или [диск][:\][путь] [ноль] = 260. Можно предположить, что 256 - это разумная фиксированная длина строки из дней DOS. Возвращаясь к API DOS, мы понимаем, что система отслеживает текущий путь на диск, и у нас есть 26 (32 с символами) максимум дисков (и текущих каталогов).
INT 0x21 AH=0x47 говорит: "Эта функция возвращает описание пути без буквы диска и начальной обратной косой черты". Таким образом, мы видим, что система сохраняет CWD в виде пары (диск, путь), и вы запрашиваете путь, указывая диск (1=A, 2=B, …), если вы укажете 0, то он принимает путь для диска, возвращенный INT 0x21 AH=0x15 AL=0x19. Итак, теперь мы знаем, почему это 260, а не 256, потому что эти 4 байта не сохраняются в строке пути.
Почему строка пути 256 байт, потому что 640 КБ достаточно ОЗУ.
Это не совсем так, поскольку файловая система NTFS поддерживает пути до 32 тыс. Символов. Вы можете использовать Win32 API и " \\?\
msgstr "префикс пути, чтобы использовать более 260 символов.
Подробное объяснение длинного пути из блога команды.Net BCL.
Небольшая выдержка подчеркивает проблему с длинными путями
Другая проблема заключается в несовместимом поведении, которое может возникнуть в результате предоставления поддержки длинного пути. Длинные пути с
\\?\
Префикс может использоваться в большинстве файловых API Windows, но не во всех Windows API. Например, LoadLibrary, который отображает модуль на адрес вызывающего процесса, завершается ошибкой, если имя файла длиннее, чем MAX_PATH. Таким образом, это означает, что MoveFile позволит вам переместить библиотеку DLL в такое место, где ее путь будет длиннее 260 символов, но при попытке загрузить библиотеку DLL произойдет сбой. Есть аналогичные примеры в Windows API; Существуют некоторые обходные пути, но они применяются в каждом конкретном случае.
Вопрос в том, почему ограничение все еще существует. Конечно, современные окна могут увеличить сторону MAX_PATH
чтобы позволить более длинные пути. Почему ограничение не было снято?
- Причина, по которой его нельзя удалить, заключается в том, что Windows пообещала, что это никогда не изменится.
Благодаря контракту API, Windows гарантировала всем приложениям, что стандартные файловые API никогда не будут возвращать путь дольше, чем 260
персонажи.
Рассмотрим следующий правильный код:
WIN32_FIND_DATA findData;
FindFileFirst("C:\Contoso\*", ref findData);
Windows гарантировала моей программе, что она заполнит мою WIN32_FIND_DATA
состав:
WIN32_FIND_DATA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
//...
TCHAR cFileName[MAX_PATH];
//..
}
Мое приложение не объявляло значение константы MAX_PATH
Windows API сделал. Мое приложение использовало это определенное значение.
Моя структура правильно определена, и только выделяет 592
Всего байт. Это означает, что я могу получить только имя файла, которое меньше 260
персонажи. Windows пообещала мне, что если я напишу свое приложение правильно, оно продолжит работать в будущем.
Если бы Windows разрешала имена файлов длиннее, чем 260
символов, то мое существующее приложение (которое правильно использовало правильный API) потерпит неудачу.
Для тех, кто призывает Microsoft изменить MAX_PATH
постоянные, они должны сначала убедиться, что ни одно из существующих приложений не дает сбой Например, я все еще владею и использую приложение Windows, которое было написано для работы в Windows 3.11. Он по-прежнему работает на 64-битной Windows 10. Это то, что дает вам обратная совместимость.
Microsoft создала способ использовать полные 32 768 имен путей; но они должны были создать новый контракт API для этого. Во-первых, вы должны использовать Shell API для перечисления файлов (так как не все файлы существуют на жестком диске или в сетевой папке).
Но они также должны не нарушать существующие пользовательские приложения. Подавляющее большинство приложений не используют API оболочки для работы с файлами. Все просто звонят FindFirstFile
/ FindNextFile
и называет это днем.
В Windows 10. вы можете снять ограничение, изменив раздел реестра.
Совет Начиная с Windows 10, версия 1607, ограничения MAX_PATH были удалены из общих функций файлов и каталогов Win32. Тем не менее, вы должны подписаться на новое поведение.
Раздел реестра позволяет вам включить или отключить новое поведение длинного пути. Чтобы включить поведение длинного пути, установите раздел реестра на
HKLM\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled
(Тип:REG_DWORD
). Значение ключа будет кэшироваться системой (для каждого процесса) после первого вызова уязвимой функции файла или каталога Win32 (список следует). Раздел реестра не будет перезагружен в течение всего жизненного цикла процесса. Чтобы все приложения в системе могли распознать значение ключа, может потребоваться перезагрузка, поскольку некоторые процессы могли начаться до того, как был установлен ключ. Раздел реестра также можно контролировать с помощью групповой политики наComputer Configuration > Administrative Templates > System > Filesystem > Enable NTFS long paths
, Вы также можете включить новое поведение длинного пути для приложения через манифест:<application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings"> <ws2:longPathAware>true</ws2:longPathAware> </windowsSettings> </application>
Вы можете смонтировать папку как диск. Из командной строки, если у вас есть путь C:\path\to\long\folder
Вы можете сопоставить его с буквой диска X:
с помощью:
subst x: \path\to\long\folder
Один из способов справиться с ограничением пути - сократить записи пути с помощью символических ссылок.
Например:
- создать
C:\p
каталог для хранения коротких ссылок на длинные пути mklink /J C:\p\foo C:\Some\Crazy\Long\Path\foo
- добавлять
C:\p\foo
на свой путь вместо длинного пути
Вы можете включить длинные имена путей, используя PowerShell:
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name LongPathsEnabled -Type DWord -Value 1
Другая версия заключается в использовании групповой политики в Computer Configuration
/Administrative Templates
/System
/Filesystem
:
Что касается того, как справиться с ограничением размера пути в Windows - использование 7zip для упаковки (и распаковки) ваших файлов, чувствительных к длине пути, кажется приемлемым обходным путем. Я использовал его для переноса нескольких инсталляций IDE (эти пути к подключаемым модулям Eclipse, yikes!) И груды автоматически сгенерированной документации, и до сих пор не было ни одной проблемы.
Не совсем уверен, как он преодолевает ограничение в 260 символов, установленное Windows (из технической точки зрения), но эй, это работает!
Более подробная информация на их странице SourceForge здесь:
"NTFS может поддерживать имена путей длиной до 32 000 символов".
7-zip также поддерживают такие длинные имена.
Но это отключено в коде SFX. Некоторым пользователям не нравятся длинные пути, так как они не понимают, как с ними работать. Вот почему я отключил его в коде SFX.
9.32 альфа 2013-12-01
- Улучшена поддержка имен файлов длиннее 260 символов.
4.44 бета 2007-01-20
- 7-Zip теперь поддерживает имена файлов длиной более 260 символов.
ВАЖНОЕ ПРИМЕЧАНИЕ. Чтобы это работало правильно, вам нужно указать путь к месту назначения в диалоговом окне "Извлечь" из 7zip, а не перетаскивать файлы в нужную папку. В противном случае папка "Temp" будет использоваться в качестве промежуточного кэша, и вы попадете в то же ограничение в 260 символов, как только Windows Explorer начнет перемещать файлы в их "окончательное место покоя". См. Ответы на этот вопрос для получения дополнительной информации.
Что касается того, почему это все еще существует - MS не считает это приоритетом и ценит обратную совместимость по сравнению с продвижением своих ОС (по крайней мере, в этом случае).
Обходной путь, который я использую, состоит в том, чтобы использовать "короткие имена" для каталогов в пути, вместо их стандартных, удобочитаемых версий. Так, например, для C:\Program Files\
я хотел бы использовать C:\PROGRA~1\
Вы можете найти эквиваленты короткого имени, используя dir /x
,
Это так, и по какой-то причине это значение по умолчанию, но вы можете легко переопределить его следующим ключом реестра:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"LongPathsEnabled"=dword:00000001
См.: https://blogs.msdn.microsoft.com/jeremykuhne/2016/07/30/net-4-6-2-and-long-paths-on-windows-10/
Другой способ справиться с этим - использовать Cygwin, в зависимости от того, что вы хотите делать с файлами (например, если команды Cygwin удовлетворяют вашим потребностям)
Например, он позволяет копировать, перемещать или переименовывать файлы, что даже Windows Explorer не может. Или, конечно, иметь дело с содержимым, таким как md5sum, grep, gzip и т. Д.
Также для программ, которые вы кодируете, вы можете связать их с Cygwin DLL, и это позволило бы им использовать длинные пути (хотя я не проверял это, хотя)
В то время как все плачут, что 260 символов ужасны в 2017 году, почему-то никто не плачет, что большинство gnu-хренов ломается, если встречает пробелы в путях. Даже не Юникод. И если говорить о по сути нарушенных функциях - подумайте о ваших любимых strcpy
без n
, Четное malloc
не работает в Linux, потому что он полагается на ошибки страницы, чтобы фактически зафиксировать зарезервированное адресное пространство (которое является медленным и подвержено ошибкам). Никто не совершенен, и невежество не является веской причиной для нытья.
Также комментаторы как-то не говорят, что именно сломано.
Есть 3 вещи, которые сломаны:
некоторые вызовы (я знаю только о Get/SetCurrentDirectoryW) ограничены одним потоком и 260 символами, несмотря ни на что. Так что по сути относительные пути нарушены в Windows, эмулируйте их так же, как вы эмулируете
fork
если вы вынуждены.программное обеспечение, портированное из не-окон, которое по своей сути опирается на не-оконные концепции (включая концепцию текущих dir / относительных путей, см. выше)
программное обеспечение, которое написано с нуля для Windows, но все еще использует древний API (но см. выше - хотя есть API для общего доступа к файловой системе, в Windows нет API для текущего каталога, который работает после MAX_PATH)
Что касается того, почему это все еще сломано - по моему мнению MS исправил все, что исправимо. Я думаю, что это наследование текущего каталога дочерними процессами, которое не позволяет исправить GetCurrentDirectoryW.