为什么Windows存在260个字符路径长度限制?

482

我曾在不合适的时候多次遇到这个问题:

  • 尝试处理深层路径的开源Java项目
  • 在源代码控制中存储深层Fitnesse wiki树
  • 使用Bazaar导入我的源代码控制树时出现错误

为什么存在此路径限制?

为什么它还没有被移除?

如何应对路径限制?不,转换到Linux或Mac OS X不是这个问题的有效答案 ;)


9
实际上,Windows(至少从Win2K开始)支持连接点(http://en.wikipedia.org/wiki/NTFS_junction_point),而Vista及以上版本支持NT符号链接(http://en.wikipedia.org/wiki/NTFS_symbolic_link)。 无论如何,虽然符号链接可以帮助使较长/嵌套的路径更友好,但如果遇到路径长度限制,我无法想象符号链接会如何有助于解决问题。 - Ashutosh Mehra
10
即使这个限制不存在,总会有很多其他限制,而每一个限制在某些时候都可能令人讨厌。问题是为什么这个限制如此之低?在8.3的年代之后,随着巨型硬件的出现,路径现在应该是一个动态分配的字符串,大小几乎没有限制。 - Roland
17
微软终于在Windows 10 Build 14352中解决了这个问题。 - Warren P
3
是的,看起来你需要修改应用程序清单(manifest)以使其支持长文件路径。 - Warren P
3
很遗憾,@PatrickSzalapski,这个问题已经得到解决。你可以在以下链接中查看详细信息:https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2156195-fix-260-character-file-name-length-limitation?tracking_code=32c8b19e00e95981623c3b65db8f21e9 - phuclv
显示剩余6条评论
11个回答

281

引用本文 https://learn.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation

最大路径长度限制

在Windows API中(以下几段有一些例外情况),路径的最大长度为MAX_PATH,它被定义为260个字符。本地路径按以下顺序结构化:驱动器号、冒号、反斜杠、由反斜杠分隔的名称组件和终止空字符。例如,在D盘上的最大路径为“D:\一些256个字符的路径字符串<NUL>”,其中"<NUL>"代表当前系统代码页的不可见终止空字符。(这里使用< >是为了视觉清晰,不能成为有效的路径字符串的一部分。)

现在我们看到它是1+2+256+1或[驱动器][:\][路径][null]= 260。可以假设256是来自DOS时代的合理固定字符串长度。回到DOS API,我们意识到系统每个驱动器跟踪当前路径,我们有26(32个符号)最大驱动器(和当前目录)。

INT 0x21 AH=0x47表示“此函数返回不带驱动器号和初始反斜杠的路径描述”。因此,我们可以看到系统将CWD存储为一对(驱动器,路径),您可以通过指定驱动器(1=A,2=B,...)来请求路径,如果指定0,则假定路径为由INT 0x21 AH=0x15 AL=0x19返回的驱动器的路径。现在我们知道为什么它是260而不是256了,因为这4个字节未存储在路径字符串中。
为什么要使用256字节的路径字符串,因为640K的RAM已足够。

29
即使在最新的操作系统中,Windows API仍然有长度限制。如果改变这一点,微软担心会破坏今天正在使用的数亿个操作系统,因为他们没有像20世纪80年代和90年代那样完全掌握API的天才人才了。风险不值得去改变它。 - Entree
102
@MacGyver 很抱歉,但那完全是无稽之谈。微软不想破坏数百万个假设系统未曾保证的应用程序。不幸的是,这种情况已经存在很长时间了,开发人员开始依赖它们,所以现在改变它会破坏第三方应用程序,而微软将受到指责。 - Basic
32
顺便提一句,没有证据表明盖茨曾经说过“640K内存对于任何人来说足够了”。http://www.computerworld.com/article/2534312 - Patrick
16
@Basic 在Windows系统中,260字符的限制是被保证的。这个常量被声明为一个“constant”(常量),Windows头文件中声明了一个结构体,仅有容纳260个字符的空间。无法更改此限制。 - Ian Boyd
44
@Basic 这个常量一旦编译进我的应用程序就不会改变。我运行的应用程序是上次在1994年构建的,现在仍然可以在Windows 10上运行。Microsoft承诺了一块内存的特定二进制大小,程序员遵循了这个规则。如果Microsoft改变了这个常量,那么所有正确遵循编程API的现有应用程序都将被破坏。你不能破坏二进制兼容性。 - Ian Boyd
显示剩余18条评论

178

这并不完全正确,因为NTFS文件系统支持长达32k个字符的路径。您可以使用win32 api和"\\?\"前缀来使用大于260个字符的路径。

关于长路径的详细解释来自.Net BCL团队博客
一个小节摘录了长路径的问题

另一个问题是公开长路径支持会导致不一致的行为。带有\\?\前缀的长路径可以在大多数与文件相关的Windows API中使用,但并非所有Windows API都支持。例如,将模块映射到调用进程的地址的LoadLibrary如果文件名超过MAX_PATH,则失败。因此,这意味着MoveFile将允许您将DLL移动到路径超过260个字符的位置,但当您尝试加载DLL时,它将失败。Windows API中存在类似的示例;一些解决方法存在,但它们是基于特定情况的。


5
好的,但这意味着你需要在很多地方使用P/Invoke,这样会降低你的.Net代码的可移植性。如果我想保持与Mono的兼容性怎么办? - Jeffrey Cameron
2
我的观点是,如果你真的想要,你可以使用长路径。但我同意这很麻烦,个人而言我也会避免使用长路径。 - softveda
9
应该选择这个答案。它实际上回答了用户提出的为什么存在这个限制并提供了一种解决方法。点赞以提高可见性。 - KyleMit
3
我认为微软需要修复他们的API,但我猜这不是他们的重点。我很惊讶这个限制在Windows 8中仍然存在。 - Mas
5
@Mas,你想要的“修复”早在Windows XP时就已经完成了。调用其API的unicode版本将允许您访问“扩展路径”。我相信资源管理器会自动处理这个问题。这是一个支持它的函数- http://msdn.microsoft.com/en-us/library/windows/desktop/aa364418(v=vs.85).aspx。 - Natalie Adams
显示剩余2条评论

154

问题在于为什么限制仍然存在。当然,现代的 Windows 可以增加 MAX_PATH 的大小以允许更长的路径。为什么这个限制没有被取消呢?

  • 无法取消限制的原因是 Windows 承诺永远不会更改。

通过 API 合同,Windows 已经保证所有应用程序,标准文件 API 永远不会返回超过 260 个字符的路径。

考虑以下正确的代码:

WIN32_FIND_DATA findData;

FindFirstFile("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 3.11 上运行的 Windows 应用程序。它仍然可以在 64 位的 Windows 10 上运行。这就是向后兼容性的好处所在。

Microsoft 确实创建了一种方法来使用完整的 32,768 路径名;但他们必须创建一个新的 API 协议来实现这一点。其中一个方法是使用Shell API枚举文件(因为不是所有的文件都存在于硬盘或网络共享中)。

但他们也必须不破坏现有的用户应用程序。绝大多数应用程序不使用 shell api 进行文件处理。每个人都只调用FindFirstFile/FindNextFile就结束了。


6
如果这样做的话,就会违反该方法最初定义的合同,这样做可能会覆盖意外的内存,并潜在地开放一个安全漏洞。唯一的解决方法是提供一个新的改进的API(如支持Unicode的版本),并“希望”每个人重新编译/重新发布所有使用新API的应用程序。 - Rowland Shaw
22
向后兼容性不错。但我认为避免今天这样(通常非常恶心的)问题比支持Windows 3.1应用程序更重要。有多少人会遇到太长的路径问题?还有多少人在使用Windows 3.1应用程序?他们甚至取消了对Windows XP的支持。那么,为什么他们不宣布,从Windows [x]及更高版本开始,那些假定路径不超过260个字符的应用程序,在遇到过长的路径时将无法按预期工作?我们的速限也不考虑马车。 - JuSchu
4
@TheincredibleJan 在 MSDN 上说:“文档创建了合同,这就是为什么你需要非常小心地记录你的文档内容的原因。” - Ian Boyd
3
这个答案混淆了最大路径组件长度和最大路径长度。对于微软文件系统,最大路径组件长度通常为255个字符,并且完全固定,而最大路径长度可以在NT中达到32760个字符,这是由于内核的UNICODE_STRING结构。使用“\?\”前缀,所有常见的文件系统(如NTFS、UDF、FAT32和exFAT)都支持完整的NT最大路径长度。260个字符的路径限制是由于DOS / Windows路径处理运行时库中的固定缓冲区(例如ANSI <=> Unicode、工作目录和DOS <=> NT路径转换)造成的。 - Eryk Sun
4
使用该解决方案,调用者在调用函数之前需要知道为FIND_DATA结构分配多少内存,这对代码大小不利。现在一个函数调用变成了两个,在查找所有文件的循环中,我刚刚使一切变慢了50%。在我的4.77MHz机器上,这样做不好。你白白地使事情变慢了50%。而且每次都要调用这个函数,并重新分配内存?那不好。假设您将拥有此可变长度数组在结构的末尾,否则我必须进行数学计算才能读取后续字段。 - Ian Boyd
显示剩余21条评论

78

在Windows 10中,您可以通过修改注册表键来移除限制

提示:从Windows 10版本1607开始,常见的Win32文件和目录函数已经移除了MAX_PATH的限制。但是,您必须选择新行为。

一个注册表键允许您启用或禁用新的长路径行为。要启用长路径行为,请设置注册表键HKLM\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled(类型:REG_DWORD)。系统会在首次调用受影响的Win32文件或目录函数(如下所示)后缓存键值(每个进程)。进程的生命周期内不会重新加载注册表键。为了使系统上的所有应用程序都能识别该键的值,可能需要重新启动计算机,因为某些进程可能在设置键值之前就已经启动。 该注册表键还可以通过组策略进行控制,位于计算机配置 > 管理模板 > 系统 > 文件系统 > 启用NTFS长路径。 您也可以通过清单为每个应用程序启用新的长路径行为:

<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>
抱歉,我只能使用英文回答。

32
可悲的是,即便在最新版本的Win10中,文件浏览器本身仍然无法处理过长的路径名问题。即使在右键菜单中选择“复制为路径”,它也不能按预期工作,只会复制前260个字符。你无法创建文件夹、复制/移动/打开文件......这让我想知道这种更改的意义何在。 - raymai97
2
请注意,声称系统设置与清单设置无关是错误的。两者都是必需的。策略必须在系统级别上启用,并且清单必须声明应用程序具有长路径感知能力。 - Eryk Sun
2
@KDP会导致与大多数32位程序、许多64位程序以及任何无法处理较长文件名的其他设备之间的兼容性问题(例如,您将无法将文件传输到/从大多数存储卡、闪存驱动器、媒体服务器/NAS、路由器、旧计算机、打印机等)。 - Synetech
@raymai97 Windows Explorer是特殊的,它使用自己的路径处理概念,并需要考虑任意附加插件。因此,启用此功能可能会使任意其他插件也启用该功能,或者它们可能会收到意外的长路径,这可能现在太冒险了。 - Thorsten Schöning
1
即使在注册表中打开了“LongPathsEnabled”键,Windows资源管理器应用程序仍然硬编码了260个字符的限制,以浏览文件夹路径。当达到限制时,如果NTFS磁盘已经打开支持短名称(例如使用dir /x显示长于8.3个字符的文件夹旁边的短名称),Windows资源管理器将尝试使用短名称(带有波浪符号)重写路径,并且当路径再次超过260时,仍然无法显示、打开或有时甚至读取Windows资源管理器应用程序内的安全设置。 - justdan23
显示剩余2条评论

36

你可以将一个文件夹挂载为驱动器。如果你有一个路径C:\path\to\long\folder,你可以使用以下命令将其映射到驱动器字母X::

subst x: \path\to\long\folder

当我尝试执行此命令时,我收到了“无效参数 j:” 的错误提示。 - barrypicker
这需要从管理员(提升)命令提示符中运行。 - Mrchief
这将因为使用了正斜杠而失败,需要改成反斜杠。 - cchamberlain
1
我不确定这是否仅适用于Windows 10,但我刚发现当尝试运行此命令时,如果像上面建议的那样以管理员身份运行,则驱动器似乎不可用。这是因为该行为类似于映射网络驱动器,并且是特定于会话的等等。因此,当我以管理员身份运行并使用此命令时,该会话可以使用x:简而言之,如果您看不到驱动器,请尝试在非管理员模式下运行该命令。 - Jaddie
4
subst 是本地会话/账户 - 参见 https://superuser.com/questions/29072/how-to-make-subst-mapping-persistent-across-reboots/29079#29079 了解如何使其“系统范围内”持久化。 - user2864740
显示剩余2条评论

20

应对路径限制的一种方法是使用符号链接缩短路径条目。

例如:

  1. 创建一个 C:\p 目录以保留指向长路径的短链接
  2. mklink /J C:\p\foo C:\Some\Crazy\Long\Path\foo
  3. C:\p\foo 添加到您的路径中,而不是长路径

4
无需先创建目录,因此步骤1不必要。 - ohaal
4
这个技巧并不总是有效,因为许多应用程序尝试解析这些链接。 - nponeccop
4
/j选项可为本地卷设备或本地卷上的路径(类似于Unix绑定挂载)创建连接点。它不会创建符号链接。这是一个重要区别,因为连接点总是在服务器上评估并必须针对本地设备,而符号链接在客户端上评估并可以指向远程路径(如果策略允许)。像subst.exe驱动器(即DefineDosDeviceW)一样,连接点目标通常限制为约4K个字符。实际上是8K个字符,大致平均分配在替代路径和显示路径之间。 - Eryk Sun
1
一个Junction是一个硬链接。Junction只能通过命令行创建。操作系统中没有UI控件来创建它们。然而,要注意使用硬链接的危险性,因为如果有人尝试复制文件并将其硬链接回其父文件夹,则可能会导致循环往复。我曾经因为有人将一个硬链接链接回根目录而失去了一块硬盘,所以当有人递归删除一个文件夹时,它会循环回来并删除整个硬盘。 - justdan23
@justdan23 有趣的漏洞!有没有一种方法可以禁止系统中的硬链接? - Satoshi Nakamoto

17

您可以使用 PowerShell 启用长路径名:

Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name LongPathsEnabled -Type DWord -Value 1 

另一种方法是在计算机配置/管理模板/系统/文件系统中使用组策略(Group Policy)

Group Policy Editor


7
每个应用程序仍然需要声明其具有长路径支持。微软在传达这一点方面做得不够好,他们让人觉得应用程序清单只是另一种启用此功能的方式,而不是清晰地解释它是操作系统(系统级策略)和应用程序之间必须达成一致的契约。 - Eryk Sun
1
即使是 Visual Studio 2019 Community,也不支持长路径,可惜。 - Pieterjan
1
即使是Windows资源管理器也不支持长路径名。当路径超过260个字符时,它会使用短名称进行伪装,但一旦达到260个字符的限制,您将无法在Windows资源管理器应用程序中查看任何文件夹或文件。您可以从其他支持32767个字符路径的应用程序和命令行访问它们,但不能从Windows资源管理器应用程序的用户界面访问它们。我很惊讶在2022年这仍然是一个问题,但我听说微软正在努力推出补丁,在Windows 10和他们的新服务器上支持尝试修复它。 - justdan23
使用MAX_PATH宏的方式已经过时了。 - Davide_24

12
对于如何应对Windows上的路径大小限制 - 使用7zip来打包(和解压缩)您的路径长度敏感文件似乎是一个可行的解决方法。我已经使用它来传输多个IDE安装(那些Eclipse插件路径,呀!)和大量自动生成的文档,到目前为止还没有遇到任何问题。
从技术角度来看,不太确定它如何规避Windows设置的260个字符限制,但是嘿,它有效!
更多细节可以在他们的SourceForge页面here中查看:
“NTFS实际上可以支持长达32,000个字符的路径名。” 7-zip也支持这样长的名称。 但是它在SFX代码中被禁用。一些用户不喜欢长路径,因为他们不知道如何处理它们。这就是为什么我在SFX代码中将其禁用的原因。
还有release notes

9.32 alpha 2013-12-01

  • 改进了对长于260个字符的文件路径名的支持。

4.44 beta 2007-01-20

  • 7-Zip现在支持长于260个字符的文件路径名。

重要提示:为了使其正常工作,您需要直接在7zip“提取”对话框中指定目标路径,而不是将文件拖放到所需文件夹中。否则,“Temp”文件夹将用作中间缓存,一旦Windows Explorer开始将文件移动到它们的“最终安息之地”,您将会遇到同样的260个字符限制。有关更多信息,请参见this question的回复。


3
我错了,7zip和WinRAR确实可以提取所有的文件夹和文件。只是Windows文件夹的属性仅报告不违反限制的文件夹和文件数。就像Windows资源管理器在达到最大路径时不会深入挖掘文件夹一样。 - Twisted Whisper
可以使用Shift+Del在7-zip中删除长路径。 - Laurie Stearn
简短回答 - 使用7zip解压缩.zip文件...在Windows 7上对我有效。 - andrewcockerham
1
请注意,2022年最新版本的7zip成功压缩了一个WIM文件,但未能正确还原WIM文件。当由7zip创建时,DISM可以正确还原WIM文件。这是需要注意的事项。在所有驱动器字母路径前使用\?\前缀,以触发7zip处理长度为32,767的ZIP或WIM文件。 - justdan23

11

至于为什么这种情况仍然存在 - 微软没有把它视作优先事项,而是将向后兼容性看得比推进其操作系统更重要(至少在这个例子中)。

我使用的一种解决方法是使用路径中目录的“短名称”,而不是它们标准的、可读性强的版本。所以如对于C:\Program Files\,我会使用C:\PROGRA~1\。可以使用dir /x查找短名称的等效项。


2
短路径名可以在注册表(或是文件系统本身?)中被禁用,因此这并不是一个可靠的解决方案。 - rubenvb
7
@rubenvb 我相信大多数甚至所有的Windows功能都可以在注册表中禁用,所以¯\(ツ)/¯。 - Conrad
1
生成短名称可以在NTFS上禁用(应该这样做,因为在许多情况下效率低下),可以针对整个系统或卷进行禁用,因此即使是系统驱动器上的路径(必须是NTFS),这也是一种不可靠的方法。在NTFS中,可以手动设置文件和目录的短名称,但这不适用于根本不支持短名称的新文件系统,例如exFAT和ReFS。应该考虑将短名称视为弃用功能,在有限的情况下保留兼容性,例如使用单字节和双字节代码页的旧ANSI/OEM API。 - Eryk Sun
1
@eryksun 请查看我之前的评论,关于禁用短路径名。:) 仅仅因为你认为它应该被视为弃用功能,并不意味着它实际上已经被弃用了。微软没有计划弃用这个功能。(另外,为什么你要在 exFAT/ReFS 分区上安装 Windows 软件?) - Conrad
我仍然建议只使用非规范化的设备路径(即“\?\”前缀),因为它们始终可用且明显。例如,将PATH翻译并传递给SearchPathW。这也很高效,因为运行时库会为NT创建“\?\”设备路径。至于较新的文件系统,我们可能不会看到安装在exFAT卷上的软件,除了便携式应用程序,因为它没有安全性,但我不排除ReFS。用户以非标准位置安装程序是出于方便、空间或性能等原因。 - Eryk Sun

8

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接