我在不合时宜的时刻遇到了几次这个问题:
尝试在具有深度路径的开源 Java 项目上工作
在源代码控制中存储深度 Fitnesse wiki 树
尝试使用 Bazaar 导入我的源代码控制树时出错
为什么存在这个限制?
为什么还没有被删除?
您如何应对路径限制?不,切换到 Linux 或 Mac OS X 不是这个问题的有效答案;)
引用这篇文章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。
这并不严格,因为 NTFS 文件系统支持最多 32k 个字符的路径。您可以使用 win32 api 和“\\?\
”前缀来使用大于 260 个字符的路径。
来自 .Net BCL team blog 的长路径的详细说明。
一小段摘录突出了长路径的问题
另一个问题是暴露长路径支持会导致不一致的行为。带有 \\?\ 前缀的长路径可用于大多数与文件相关的 Windows API,但并非所有 Windows API。例如,如果文件名长于 MAX_PATH,则将模块映射到调用进程的地址的 LoadLibrary 会失败。因此,这意味着 MoveFile 将允许您将 DLL 移动到其路径长度超过 260 个字符的位置,但是当您尝试加载 DLL 时,它会失败。在整个 Windows API 中都有类似的示例;存在一些解决方法,但它们是根据具体情况而定的。
问题是为什么限制仍然存在。当然,现代 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
就可以了。
UNICODE_STRING
结构,在 NT 中最多可以有 32,760 个字符。使用“\\?\”前缀,所有常见的文件系统,如 NTFS、UDF、FAT32 和 exFAT 都支持完整的 NT 最大路径长度。 260 个字符的路径限制是由于 DOS/Windows 路径处理的运行时库中的固定缓冲区(例如 ANSI <=> Unicode、工作目录和 DOS<=>NT 路径转换)。
从 Windows 10 开始。您可以通过修改注册表项来remove the limitation。
提示 从 Windows 10 版本 1607 开始,MAX_PATH 限制已从常见的 Win32 文件和目录函数中删除。但是,您必须选择加入新行为。注册表项允许您启用或禁用新的长路径行为。要启用长路径行为,请将注册表项设置为 HKLM\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled(类型:REG_DWORD)。在第一次调用受影响的 Win32 文件或目录函数(列表如下)后,系统(每个进程)将缓存该键的值。在进程的生命周期内不会重新加载注册表项。为了让系统上的所有应用程序都能识别密钥的值,可能需要重新启动,因为某些进程可能在设置密钥之前已经启动。注册表项也可以通过计算机配置 > 管理模板 > 系统 > 文件系统 > 启用 NTFS 长路径中的组策略进行控制。您还可以通过清单为每个应用启用新的长路径行为:
您可以将文件夹挂载为驱动器。从命令行,如果您有路径 C:\path\to\long\folder
,您可以使用以下方法将其映射到驱动器号 X:
:
subst x: \path\to\long\folder
subst
是本地会话/帐户 - 请参阅 superuser.com/questions/29072/… 了解如何使其成为“系统范围”
解决路径限制的一种方法是使用符号链接缩短路径条目。
例如:
创建一个 C:\p 目录以保留指向长路径的短链接 mklink /JC:\p\foo C:\Some\Crazy\Long\Path\foo 将 C:\p\foo 添加到您的路径而不是长路径
/j
选项为本地卷设备或本地卷上的路径创建连接挂载点(如 Unix 绑定挂载)。它不会创建符号链接。这是一个重要的区别,因为连接挂载点始终在服务器上评估并且必须以本地设备为目标,而符号链接在客户端上评估并且可能以远程路径为目标(如果策略允许)。与 subst.exe 驱动器(即 DefineDosDeviceW
)一样,连接目标通常限制为大约 4K 字符。它实际上是 8K 个字符,在替代路径和显示路径之间平均分配。
您可以使用 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
至于为什么这仍然存在 - MS 不认为它是优先事项,并且重视向后兼容性而不是推进他们的操作系统(至少在这种情况下)。
我使用的一种解决方法是对路径中的目录使用“短名称”,而不是使用它们的标准、人类可读的版本。所以 eg 对于 C:\Program Files\
我会使用 C:\PROGRA~1\
您可以使用 dir /x
找到等效的短名称。
PATH
并将其传递给 SearchPathW
。它也很有效,因为运行时库无论如何都会为 NT 创建 "\\?\" 设备路径。至于较新的文件系统,我们可能不会看到安装在 exFAT 卷上的软件,除了便携式应用程序,因为它没有安全性,但我不排除 ReFS。出于方便、空间或性能的原因,用户将程序安装在非标准位置。
至于如何应对 Windows 上的路径大小限制 - 使用 7zip 打包(和解包)您的路径长度敏感文件似乎是一种可行的解决方法。我已经用它来传输几个 IDE 安装(那些 Eclipse 插件路径,哎呀!)和成堆的自动生成的文档,到目前为止还没有遇到任何问题。
不太确定它如何规避 Windows 设置的 260 字符限制(来自技术 PoV),但是,嘿,它有效!
有关其 SourceForge 页面 here 的更多详细信息:
“NTFS 实际上可以支持长达 32,000 个字符的路径名。” 7-zip 也支持这么长的名字。但它在 SFX 代码中被禁用。一些用户不喜欢长路径,因为他们不了解如何使用它们。这就是我在 SFX 代码中禁用它的原因。
9.32 alpha 2013-12-01 改进了对超过 260 个字符的文件路径名的支持。 4.44 beta 2007-01-20 7-Zip 现在支持超过 260 个字符的文件路径名。
重要提示:要使其正常工作,您需要直接在 7zip“提取”对话框中指定目标路径,而不是拖动 &将文件放入预期的文件夹中。否则,“Temp”文件夹将用作临时缓存,一旦 Windows 资源管理器开始将文件移动到它们的“最终存放位置”,您将退回到相同的 260 字符限制。有关详细信息,请参阅对 this question 的回复。
确实如此,并且由于某种原因它是默认设置,但您可以使用以下注册表项轻松覆盖它:
[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 资源管理器也不能。或者当然处理它们的内容,如 md5sum、grep、gzip 等。
同样对于您正在编码的程序,您可以将它们链接到 Cygwin DLL,这将使它们能够使用长路径(虽然我还没有测试过)