ChatGPT解决这个技术问题 Extra ChatGPT

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

我在不合时宜的时刻遇到了几次这个问题:

尝试在具有深度路径的开源 Java 项目上工作

在源代码控制中存储深度 Fitnesse wiki 树

尝试使用 Bazaar 导入我的源代码控制树时出错

为什么存在这个限制?

为什么还没有被删除?

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

@Artelius:实际上,Windows(至少从 Win2K 起)确实支持连接点(en.wikipedia.org/wiki/NTFS_junction_point),而 Vista 起支持 NT 符号链接(en.wikipedia.org/wiki/NTFS_symbolic_link)。无论如何,虽然符号链接可以帮助使更长/嵌套的路径更友好,但如果你达到路径长度限制,我想不出符号链接会有什么帮助。
即使这个限制不存在,也总会有很多其他的限制,而且每一个都可能在某些时候令人讨厌。关键是为什么这个限制这么低?在 8.3 时代之后,使用兆/千兆大小的硬件,路径现在应该是动态分配的字符串,大小几乎不受限制。
微软终于在 Windows 10 Build 14352 中解决了这个问题。
是的,看起来您必须修改应用程序清单以使其具有长路径意识。
@PatrickSzalapski 不幸的是它已修复visualstudio.uservoice.com/forums/121579-visual-studio/…

J
John Cummings

引用这篇文章https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation

最大路径长度限制 在 Windows API 中(以下段落中讨论了一些例外情况),路径的最大长度为 MAX_PATH,定义为 260 个字符。本地路径按以下顺序构造:驱动器号、冒号、反斜杠、由反斜杠分隔的名称组件和终止空字符。例如,驱动器 D 上的最大路径是“D:\some 256-character path string”,其中“”表示当前系统代码页的不可见终止空字符。 (字符 < > 在此处用于视觉清晰,不能作为有效路径字符串的一部分。)

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

INT 0x21 AH=0x47 表示“此函数返回不带驱动器号和初始反斜杠的路径描述。”所以我们看到系统将 CWD 存储为一对(驱动器,路径),您通过指定驱动器(1=A,2=B,...)来询问路径,如果您指定 0,那么它假定路径为INT 0x21 AH=0x15 AL=0x19 返回的驱动器。所以现在我们知道为什么它是 260 而不是 256,因为这 4 个字节没有存储在路径字符串中。

为什么是 256 字节的路径字符串,因为 640K 足够 RAM。


即使在最新的操作系统中,Windows API 也会限制长度。如果这种情况发生变化,微软害怕破坏今天使用的数亿个操作系统,因为他们不再有天才为他们工作,他们能够从内到外理解 API,就像他们在 1980 年代和 1990 年代所做的那样。风险不值得改变。 serverfault.com/questions/163419/…
@MacGyver对不起,但这完全是胡说八道。微软不想破坏数以百万计的写得不好的应用程序,这些应用程序假设有关系统的事情从未得到保证。不幸的是,事情一直如此,以至于开发人员开始依赖它们,所以现在改变它会破坏 3rd 方应用程序,MS 会受到指责。
顺便说一句,没有证据表明盖茨曾说过“640K Ram 对每个人都足够了”computerworld.com/article/2534312
@Basic Windows 保证 260 个字符的限制。该常量被声明为常量,在 Windows 头文件中声明了一个结构,它只有 260 个字符的空间。没有办法改变它。
@Basic 常量一旦编译到我的应用程序中就不会改变。我运行了一个应用程序,该应用程序最后一次构建于 1994 年,并且今天仍在 Windows 10 中运行。微软承诺一定的二进制大小的内存块,程序员遵循了这个规则。如果微软要改变这个常数,那么每一个正确遵循编程 API 的现有应用程序都会被破坏。您不能破坏二进制兼容性。
d
dthorpe

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

来自 .Net BCL team blog 的长路径的详细说明。
一小段摘录突出了长路径的问题

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


很公平,但这意味着您必须在很多地方使用 P/Invoke,在我看来,这会降低您的 .Net 代码的可移植性。如果我想保持 Mono 兼容性怎么办?
我的观点是,如果你真的想的话,你可以使用长路径。但我同意这是一种痛苦,我个人也会避免这种情况。
这应该是选择的答案。实际上回答了为什么存在此限制的用户提出的问题并提供了解决方法。为可见性投票
在我看来,微软需要修复他们的 API,我想这不是优先事项。我很惊讶这个限制在 Windows 8 中仍然存在。
@Mas 您想要的“修复”完全可以追溯到 Windows XP。调用其 API 的 unicode 版本将允许您访问“扩展路径”。我相信资源管理器会自动处理这个问题。这是一个支持它的函数 - msdn.microsoft.com/en-us/library/windows/desktop/…
J
Jonathan Potter

问题是为什么限制仍然存在。当然,现代 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 上运行。这就是向后兼容性为您带来的好处。

微软确实创造了一种使用完整的 32,768 个路径名的方法;但他们必须创建一个新的 API 合约才能做到这一点。一方面,您应该使用 Shell API 来枚举文件(因为并非所有文件都存在于硬盘驱动器或网络共享上)。

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


@JosiahKeller 如果确实如此,它将破坏最初为该方法定义的合同,并且这样做可能会覆盖意外的内存,并可能会打开一个安全漏洞。解决此问题的唯一方法是提供新的改进 API(如 Unicode 感知变体),并希望每个人都使用更新的 API 重新编译/重新发布所有应用程序。
向后兼容性很好。但我认为今天避免此类(通常是非常讨厌的)问题比支持 Windows 3.1 应用程序更重要。有多少人遇到过长路径的问题?还有多少人仍在使用 Windows 3.1 应用程序?他们甚至取消了对 Windows XP 的支持。那么,他们为什么不直接宣布,Windows [x] 和更高版本的应用程序假设路径不会超过 260 个字符,当它们遇到过长的路径时将无法按预期工作?我们的速度限制也不考虑车厢。
这个答案混淆了最大路径 component 长度,对于 MS 文件系统和 完全固定,它通常是 255 个字符,最大 path 长度可以由于内核的 UNICODE_STRING 结构,在 NT 中最多可以有 32,760 个字符。使用“\\?\”前缀,所有常见的文件系统,如 NTFS、UDF、FAT32 和 exFAT 都支持完整的 NT 最大路径长度。 260 个字符的路径限制是由于 DOS/Windows 路径处理的运行时库中的固定缓冲区(例如 ANSI <=> Unicode、工作目录和 DOS<=>NT 路径转换)。
@КонстантинВан 使用该解决方案,调用者需要知道在调用函数之前为 FIND_DATA 结构分配多少内存?这对代码大小不利。现在一个函数调用变成了两个,在查找所有文件的循环中,我刚刚让一切都慢了 50%。在我的 4.77MHz 机器上,这不好。你让事情变慢了 50%。而且我每次都必须调用它,并且每次都重新分配内存?那不好。大概你会在 hte 结构的末尾有这个可变长度数组,否则我必须做数学才能读取后续字段。
r
riQQ

从 Windows 10 开始。您可以通过修改注册表项来remove the limitation

提示 从 Windows 10 版本 1607 开始,MAX_PATH 限制已从常见的 Win32 文件和目录函数中删除。但是,您必须选择加入新行为。注册表项允许您启用或禁用新的长路径行为。要启用长路径行为,请将注册表项设置为 HKLM\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled(类型:REG_DWORD)。在第一次调用受影响的 Win32 文件或目录函数(列表如下)后,系统(每个进程)将缓存该键的值。在进程的生命周期内不会重新加载注册表项。为了让系统上的所有应用程序都能识别密钥的值,可能需要重新启动,因为某些进程可能在设置密钥之前已经启动。注册表项也可以通过计算机配置 > 管理模板 > 系统 > 文件系统 > 启用 NTFS 长路径中的组策略进行控制。您还可以通过清单为每个应用启用新的长路径行为: true


可悲的是,即使在最新版本的 Win10 中,文件资源管理器本身仍然存在处理长路径名的问题。甚至上下文菜单中的“复制为路径”也无法按预期工作;它只复制前 260 个字符。你不能创建文件夹,复制/移动/打开文件......让我想知道这个改变有什么意义。
请注意,系统设置独立于清单设置的说法是错误的。两者都是必需的。该策略必须在系统级别启用,并且清单必须声明应用程序是长路径感知的。
我读到进行此更改可能会导致与较旧的 32 位应用程序的兼容性问题,但是这种兼容性问题是否常见?我想自己做出改变。 lifehacker.com/…
@KDP,它与大多数 32 位程序、许多 64 位程序以及任何其他无法处理较长文件名的设备(即,您将无法将文件传输到 /从大多数存储卡、闪存驱动器、媒体服务器/NAS、路由器、旧计算机、打印机等...)
@Synetech 事情还不错,因为首先清单控制一个具体应用程序是否能够使用更长的路径或根本不使用。其次,要解决问题,您需要更长的路径来获取不支持这些路径的应用程序。首先,在某些存储上不太可能有长的、不兼容的路径,之后使用与这些路径不兼容的应用程序。为什么要这样做?文件是如何最终存在的等等?
B
BaCaRoZzo

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

subst x: \path\to\long\folder

我在尝试此命令时收到“无效的参数 j:”
这需要从管理员(提升的)命令提示符运行。
这将因正斜杠而失败,需要是反斜杠。
我不确定这是否仅适用于 Windows 10,但是我发现在尝试运行此命令时,如果我按照上面的建议以管理员身份运行,则驱动器似乎不可用。这是因为该行为似乎类似于映射网络驱动器并且是特定于会话的等,因此当我以管理员身份运行并使用此命令时,该会话可以使用 x: TL;DR 如果您看不到驱动器,请尝试在管理员模式下运行命令。
subst 是本地会话/帐户 - 请参阅 superuser.com/questions/29072/… 了解如何使其成为“系统范围”
B
BaCaRoZzo

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

例如:

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


不必先创建目录,因此不需要第 1 步。
这个技巧并不总是有效,因为许多应用程序试图解析链接
/j 选项为本地卷设备或本地卷上的路径创建连接挂载点(如 Unix 绑定挂载)。它不会创建符号链接。这是一个重要的区别,因为连接挂载点始终在服务器上评估并且必须以本地设备为目标,而符号链接在客户端上评估并且可能以远程路径为目标(如果策略允许)。与 subst.exe 驱动器(即 DefineDosDeviceW)一样,连接目标通常限制为大约 4K 字符。它实际上是 8K 个字符,在替代路径和显示路径之间平均分配。
一个路口是一个硬链接。只能从命令行进行连接。操作系统中没有 UI 控件来创建它们。但是,请注意使用硬链接的危险,因为如果有人试图将硬链接的文件复制回其父文件夹,它们可能会导致循环。我丢失了一个硬盘驱动器,因为有人创建了一个回到根目录的硬链接,所以当有人递归删除一个文件夹时,它会循环回来并删除整个硬盘驱动器。
P
Peter Mortensen

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

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

另一个版本是在 Computer Configuration/Administrative Templates/System/Filesystem 中使用 Group Policy

https://i.stack.imgur.com/sifwu.png


每个应用程序仍然必须声明它是长路径感知的。微软在传达这一点方面做得很糟糕,它让应用程序清单看起来只是启用此功能的另一种方式,而不是清楚地解释它是操作系统(系统级策略)和应用程序之间必须达成一致的合同。
可悲的是,即使是 Visual Studio 2019 社区也不支持长路径
甚至 Windows 资源管理器也不支持长路径名。当路径超过 260 时,它会使用短名称来伪造它,但是一旦达到 260 的限制,您就无法使用 Windows 资源管理器应用程序看到下面的任何文件夹或文件。您可以从为支持 32767 路径和命令行而编写的其他应用程序访问它们,但不能从 Windows 资源管理器应用程序的 UI 访问它们。我很惊讶在 2022 年这仍然是一个问题,但我听说微软正在努力在 Windows 10 和他们的新服务器中推出一个补丁,以支持尝试修复它。
C
Conrad

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

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


可以在注册表中禁用短路径名(或者它是文件系统本身?),所以这确实不是一个可靠的解决方法。
@rubenvb 我敢肯定,如果不是所有 Windows 功能,大多数情况下都可以在注册表中禁用,所以¯\_(ツ)_/¯
可以为整个系统或每个卷禁用 NTFS 生成短名称(并且应该是因为它在许多情况下效率低下),因此即使对于必须是 NTFS 的系统驱动器上的路径,它也是一种不可靠的方法。可以在 NTFS 中手动设置文件和目录的短名称,但这不会扩展到根本不支持短名称的较新文件系统,例如 exFAT 和 ReFS。短名称应被视为已弃用的功能,为了在有限的情况下保持兼容性而保留,例如使用单字节和双字节代码页的旧 ANSI/OEM API。
@eryksun 请参阅我之前关于禁用短路径名的评论。 :) 仅仅因为您认为它应该被弃用,并不意味着它实际上是。 MS 没有计划弃用此功能。 (另外,你为什么要在 exFAT/ReFS 分区上安装 Windows 软件?)
我仍然说只使用非规范化的设备路径(即“\\?\”前缀),因为它们总是可用且显而易见的。例如,翻译 PATH 并将其传递给 SearchPathW。它也很有效,因为运行时库无论如何都会为 NT 创建 "\\?\" 设备路径。至于较新的文件系统,我们可能不会看到安装在 exFAT 卷上的软件,除了便携式应用程序,因为它没有安全性,但我不排除 ReFS。出于方便、空间或性能的原因,用户将程序安装在非标准位置。
C
Community

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

不太确定它如何规避 Windows 设置的 260 字符限制(来自技术 PoV),但是,嘿,它有效!

有关其 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 资源管理器开始将文件移动到它们的“最终存放位置”,您将退回到相同的 260 字符限制。有关详细信息,请参阅对 this question 的回复。


我错了,7zip 和 WinRAR 确实解压缩了所有文件夹和文件。只是Windows中文件夹的属性只报告不违反限制的文件夹和文件的数量。就好像 Windows 资源管理器在达到最大路径时不会深入挖掘来发现文件夹。
可以使用 shift-del 删除 7-zip 中的长路径。
简短的回答 - 使用 7zip 解压缩 .zip 文件....在 Windows 7 上为我工作
谨防 7zip 作为 2022 年的最新版本,成功压缩了 WIM 文件,但未能正确恢复 WIM 文件。 DISM 在由 7zip 创建时正确恢复了 WIM 文件。需要注意的事情。在所有驱动器号路径前使用 \\?\ 前缀来触发 7zip 以使用 32,767 长度的 ZIP 或 WIM 路径。
s
shA.t

确实如此,并且由于某种原因它是默认设置,但您可以使用以下注册表项轻松覆盖它:

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


e
eliblanco87

处理它的另一种方法是使用 Cygwin,具体取决于您要对文件执行的操作(即,如果 Cygwin 命令适合您的需要)

例如,它允许复制、移动或重命名文件,即使是 Windows 资源管理器也不能。或者当然处理它们的内容,如 md5sum、grep、gzip 等。

同样对于您正在编码的程序,您可以将它们链接到 Cygwin DLL,这将使它们能够使用长路径(虽然我还没有测试过)


它如何避免限制?它不依赖于底层文件系统(不是一个修辞问题)吗?你测试了吗?您有可以添加到答案中的参考吗? (但没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的。)
Windows 命令行确实支持 32,767 个路径长度。问题在于使用旧版 WIN32 API 的旧版应用程序,该 API 仅支持硬编码,编译时限制为 260 个字符。 Windows 资源管理器 UI 应用程序是问题所在。它仍然使用旧的 WIN32 API,并且不支持覆盖 PATH 以使用 UNC PATH。虽然 UI 采用 UNC PATH,但它会在您按下回车键并将其更改回来后对其进行重构,然后在长路径上失败(即使在启用时重构为短名称后)。我尝试过这个。