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

我有几次在不合时宜的时候遇到过这个问题:

  • 尝试在具有深度路径的开源Java项目上工作
  • 在源代码控制中存储深度fitness wiki树
  • 试图使用Bazaar导入源代码控制树时出错

为什么会有这个限制?

为什么它还没有被移除?

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

382867 次浏览

引用本文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或[drive][:\][path][null] = 260。从DOS时代开始,人们可以假设256是一个合理的固定字符串长度。回到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的内存足够了。

这并不是严格意义上的,因为NTFS文件系统支持最多32k个字符的路径。你可以使用win32 api和“\\?\”作为路径前缀来使用大于260个字符的前缀。

. net BCL团队博客中的长路径的详细解释 一个小的摘录强调了长路径的问题

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

您可以将文件夹作为驱动器挂载。在命令行中,如果你有一个路径C:\path\to\long\folder,你可以使用以下方法将它映射到驱动器号X::

subst x: \path\to\long\folder

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

例如:

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

至于为什么,这个仍然存在- MS不认为它是一个优先级,并且重视向后兼容性而不是改进他们的操作系统(至少在这种情况下)。

我使用的一种变通方法是为路径中的目录使用“短名称”,而不是使用标准的、人类可读的版本。因此,如。对于C:\Program Files\,我将使用C:\PROGRA~1\。你可以使用dir /x找到短名称等价物。

问题是为什么限制是否仍然存在。当然,现代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)将失败。

对于任何要求微软更改MAX_PATH常量的人来说,他们首先需要确保现有的应用程序没有失败。例如,我仍然拥有并使用一个在Windows 3.11上运行的Windows应用程序。它仍然运行在64位的Windows 10上。这就是向后兼容性带给你的。

微软做了创建了一种使用完整的32,768个路径名的方法;但他们必须创建一个新的API合约来做这件事。首先,你应该使用壳牌API来枚举文件(因为不是所有的文件都存在于硬盘驱动器或网络共享中)。

但是它们也不能破坏现有的用户应用程序。绝大多数做的应用程序使用shell api进行文件工作。每个人都只需要调用FindFirstFile/FindNextFile就可以了。

至于如何应对Windows上的路径大小限制,使用7 zip来打包(和解包)路径长度敏感的文件似乎是一个可行的解决方案。我已经使用它传输了几个IDE安装(那些Eclipse插件路径,哎呀!)和大量自动生成的文档,到目前为止还没有遇到任何问题。

不知道它是如何逃避260字符限制设置由Windows(从技术PoV),但嘿,它工作!

更多详细信息,请参阅他们的SourceForge页面在这里:

NTFS实际上可以支持多达32,000个字符的路径名 长度。" < / p >

7-zip也支持这样长的名称。

但是它在SFX代码中被禁用。有些用户不喜欢长路径,因为 他们不知道如何和他们一起工作。这就是我这么做的原因 在SFX代码中禁用它

发布说明:

9.32 alpha 2013-12-01

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

4.44 beta 2007-01-20

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

为了正常工作,你需要在7 zip "Extract"对话框中直接指定目标路径,而不是拖拽&将文件放入预期的文件夹。否则,“Temp”文件夹将被用作临时缓存,一旦Windows资源管理器开始将文件移动到“最终休息位置”,你就会陷入同样的260个字符限制。有关更多信息,请参阅这个问题的回复。

从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来控制。 你也可以通过manifest:

为每个应用启用新的长路径行为
<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>

另一种处理方法是使用Cygwin,这取决于您想对文件做什么(即Cygwin命令是否适合您的需要)

例如,它允许复制、移动或重命名连Windows资源管理器都做不到的文件。当然,也可以处理它们的内容,如md5sum、grep、gzip等。

此外,对于你正在编写的程序,你可以将它们链接到Cygwin DLL,这将使它们能够使用长路径(我还没有测试这个)

它确实如此,而且出于某种原因,它是默认的,但你可以很容易地用这个注册表项覆盖它:

[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/

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

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

另一个版本是在Computer Configuration/Administrative Templates/System/Filesystem中使用组策略:

组策略编辑器