我在不合时宜的时刻遇到了几次这个问题:
- 尝试处理具有深层路径的开源Java项目
- 在源代码管理中存储Deep Fitnesse Wiki树
- 尝试使用Bazaar导入我的源代码管理树时出错
为什么存在此限制?
为什么还没有删除它?
您如何应对路径限制?不,切换到Linux或Mac OS X并不是此问题的有效答案;)
我在不合时宜的时刻遇到了几次这个问题:
为什么存在此限制?
为什么还没有删除它?
您如何应对路径限制?不,切换到Linux或Mac OS X并不是此问题的有效答案;)
Answers:
引用本文https://docs.microsoft.com/zh-cn/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足够的RAM。
由于NTFS文件系统最多支持32k个字符的路径,因此这并非严格如此。您可以使用win32 api和“ \\?\
”作为路径前缀,以使用超过260个字符。
.Net BCL团队博客的详细解释。
一小段摘录突出了长途问题
另一个令人担忧的问题是,由于暴露长途支持而导致的行为不一致。具有
\\?\
前缀的长路径可以在大多数与文件相关的Windows API中使用,但不能在所有Windows API中使用。例如,如果文件名长于MAX_PATH,则将模块映射到调用进程地址的LoadLibrary失败。因此,这意味着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上运行。这就是向后兼容的优势。
微软确实创造了一种使用完整的32,768个路径名的方法。但是他们必须创建一个新的API合同才能做到这一点。首先,您应该使用Shell API枚举文件(因为并非所有文件都存在于硬盘驱动器或网络共享中)。
但是它们也不必破坏现有的用户应用程序。绝大多数应用程序不使用shell api进行文件工作。每个人都打电话给FindFirstFile
/ FindNextFile
并每天打电话。
在Windows 10中,您可以通过修改注册表项来消除限制。
提示 从Windows 10版本1607开始,MAX_PATH限制已从常见的Win32文件和目录功能中删除。但是,您必须选择加入新行为。
注册表项允许您启用或禁用新的长路径行为。要启用长路径行为,请将注册表项设置为
HKLM\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled
(Type:)REG_DWORD
。第一次调用受影响的Win32文件或目录函数(列表如下)后,键值将由系统缓存(按进程)。在该过程的生存期内,将不会重新加载注册表项。为了使系统上的所有应用都能识别密钥的值,可能需要重新启动,因为在设置密钥之前可能已经启动了某些进程。注册表项还可以通过位于的组策略来控制Computer Configuration > Administrative Templates > System > Filesystem > Enable NTFS long paths
。您还可以通过清单来为每个应用启用新的长路径行为:<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
是本地会话/帐户- 有关如何使其“系统级”的信息,请参见superuser.com/questions/29072/…–
解决路径限制的一种方法是缩短具有符号链接的路径条目。
例如:
C:\p
目录以保留指向长路径的短链接mklink /J C:\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
:
至于为什么它仍然存在-MS并不认为它是优先事项,并且相对于升级其OS(至少在这种情况下),重视向后兼容性。
我使用的一种解决方法是对路径中的目录使用“短名称”,而不是其标准的,人类可读的版本。因此,例如,对于C:\Program Files\
我将使用,C:\PROGRA~1\
您可以使用来找到短名称的等效项dir /x
。
PATH
并将其传递给SearchPathW
。这也是有效的,因为运行时库无论如何都会为NT创建“ \\?\”设备路径。对于较新的文件系统,除便携式应用程序外,我们可能不会在exFAT卷上看到安装的软件,因为它没有安全性,但我不排除ReFS。出于方便,空间或性能的考虑,用户将程序安装在非标准位置。
至于如何应对Windows上的路径大小限制-使用7zip打包(和解压缩)您的路径长度敏感文件似乎是一个可行的解决方法。我用它来传输多个IDE安装程序(那些Eclipse插件路径,yikes!)和成堆的自动生成的文档,到目前为止,还没有一个单一的问题。
不太确定它如何规避Windows设置的260个字符限制(从技术PoV),但是嘿,它起作用了!
有关其SourceForge页面的更多详细信息,请点击此处:
“ NTFS实际上可以支持最多32,000个字符的路径名。”
7-zip也支持这种长名称。
但是在SFX代码中已将其禁用。一些用户不喜欢漫长的道路,因为他们不了解如何使用它们。这就是为什么我在SFX代码中禁用了它。
和发行说明:
9.32 alpha 2013-12-01
- 改进了对长度超过260个字符的文件路径名的支持。
4.44 beta 2007年1月20日
- 7-Zip现在支持超过260个字符的文件路径名。
重要说明:为了使其正常工作,您需要直接在7zip “提取”对话框中指定目标路径,而不是将文件拖放到预期的文件夹中。否则,“临时”文件夹将用作临时缓存,一旦Windows资源管理器开始将文件移至其“最终放置位置”,您将跳回相同的260个字符限制。有关更多信息,请参见对此问题的答复。
确实如此,由于某种原因它是默认值,但是您可以使用此注册表项轻松覆盖它:
[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,这将使它们能够使用长路径(尽管我尚未对此进行测试)