我曾在不合适的时候多次遇到这个问题:
- 尝试处理深层路径的开源Java项目
- 在源代码控制中存储深层Fitnesse wiki树
- 使用Bazaar导入我的源代码控制树时出现错误
为什么存在此路径限制?
为什么它还没有被移除?
如何应对路径限制?不,转换到Linux或Mac OS X不是这个问题的有效答案 ;)
我曾在不合适的时候多次遇到这个问题:
为什么存在此路径限制?
为什么它还没有被移除?
如何应对路径限制?不,转换到Linux或Mac OS X不是这个问题的有效答案 ;)
最大路径长度限制
在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个字节未存储在路径字符串中。这并不完全正确,因为NTFS文件系统支持长达32k个字符的路径。您可以使用win32 api和"\\?\
"前缀来使用大于260个字符的路径。
关于长路径的详细解释来自.Net BCL团队博客。
一个小节摘录了长路径的问题
另一个问题是公开长路径支持会导致不一致的行为。带有
\\?\
前缀的长路径可以在大多数与文件相关的Windows API中使用,但并非所有Windows API都支持。例如,将模块映射到调用进程的地址的LoadLibrary如果文件名超过MAX_PATH,则失败。因此,这意味着MoveFile将允许您将DLL移动到路径超过260个字符的位置,但当您尝试加载DLL时,它将失败。Windows API中存在类似的示例;一些解决方法存在,但它们是基于特定情况的。
问题在于为什么限制仍然存在。当然,现代的 Windows 可以增加 MAX_PATH
的大小以允许更长的路径。为什么这个限制没有被取消呢?
通过 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
就结束了。
UNICODE_STRING
结构。使用“\?\”前缀,所有常见的文件系统(如NTFS、UDF、FAT32和exFAT)都支持完整的NT最大路径长度。260个字符的路径限制是由于DOS / Windows路径处理运行时库中的固定缓冲区(例如ANSI <=> Unicode、工作目录和DOS <=> NT路径转换)造成的。 - Eryk Sun在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>
你可以将一个文件夹挂载为驱动器。如果你有一个路径C:\path\to\long\folder
,你可以使用以下命令将其映射到驱动器字母X:
:
subst x: \path\to\long\folder
subst
是本地会话/账户 - 参见 https://superuser.com/questions/29072/how-to-make-subst-mapping-persistent-across-reboots/29079#29079 了解如何使其“系统范围内”持久化。 - user2864740应对路径限制的一种方法是使用符号链接缩短路径条目。
例如:
C:\p
目录以保留指向长路径的短链接mklink /J C:\p\foo C:\Some\Crazy\Long\Path\foo
C:\p\foo
添加到您的路径中,而不是长路径/j
选项可为本地卷设备或本地卷上的路径(类似于Unix绑定挂载)创建连接点。它不会创建符号链接。这是一个重要区别,因为连接点总是在服务器上评估并必须针对本地设备,而符号链接在客户端上评估并可以指向远程路径(如果策略允许)。像subst.exe驱动器(即DefineDosDeviceW
)一样,连接点目标通常限制为约4K个字符。实际上是8K个字符,大致平均分配在替代路径和显示路径之间。 - Eryk Sun您可以使用 PowerShell 启用长路径名:
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name LongPathsEnabled -Type DWord -Value 1
另一种方法是在计算机配置/管理模板/系统/文件系统中使用组策略(Group Policy):
重要提示:为了使其正常工作,您需要直接在7zip“提取”对话框中指定目标路径,而不是将文件拖放到所需文件夹中。否则,“Temp”文件夹将用作中间缓存,一旦Windows Explorer开始将文件移动到它们的“最终安息之地”,您将会遇到同样的260个字符限制。有关更多信息,请参见this question的回复。
至于为什么这种情况仍然存在 - 微软没有把它视作优先事项,而是将向后兼容性看得比推进其操作系统更重要(至少在这个例子中)。
我使用的一种解决方法是使用路径中目录的“短名称”,而不是它们标准的、可读性强的版本。所以如对于C:\Program Files\
,我会使用C:\PROGRA~1\
。可以使用dir /x
查找短名称的等效项。
PATH
翻译并传递给SearchPathW
。这也很高效,因为运行时库会为NT创建“\?\”设备路径。至于较新的文件系统,我们可能不会看到安装在exFAT卷上的软件,除了便携式应用程序,因为它没有安全性,但我不排除ReFS。用户以非标准位置安装程序是出于方便、空间或性能等原因。 - Eryk Sun确实如此,这是某种默认设置,但您可以轻松地使用此注册表键覆盖它:
[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/