windows MAX_PATH 问题
windows MAX_PATH 问题
引言
在win端实际发开过程中(不管是win端sdk还是electron),经常会遇到超长路径的问题(超过MAX_PATH定义的长度),一般解决问题的方式是长路径支持,但由于windows平台兼容的特殊性,长路径在某些系统API场景下依然有不少的限制,本文浅述win端长路径的兼容方案及在长路径支持时可能会遇到的一些问题及解决方案,供遇到此问题者参考参考.
1.windows MAX_PATH
微软在windows 10.1607版本中才正式启用系统长路径支持,在此之前的版本,通过MAX_PATH标识文件路径的最大长度。MAX_PATH的宏定义可以通过#include <windows.h>
引入
MAX_PATH的结构: 驱动器号、冒号、反斜杠、以反斜杠分隔的名称部分以及终止空字符。
有MAX_PATH限制的windows API:
- 目录相关API
- CreateDirectoryW
- CreateDirectoryExW
- GetCurrentDirectoryW
- RemoveDirectoryW
- SetCurrentDirectoryW
- 文件管理相关API
- CopyFileW、CopyFile2
- CopyFileExW、CreateFileW、CreateFile2
- CreateHardLinkW、CreateSymbolicLinkW
- DeleteFileW
- FindFirstFileW、FindFirstFileExW、FindNextFileW
- GetFileAttributesW、GetFileAttributesExW、SetFileAttributesW
- GetFullPathNameW、GetLongPathNameW
- MoveFileW、MoveFileExW、MoveFileWithProgressW
- ReplaceFileW、SearchPathW
- FindFirstFileNameW、FindNextFileNameW
- FindFirstStreamW、FindNextStreamW
- GetCompressedFileSizeW
- GetFinalPathNameByHandleW
2.突破MAX_PATH限制
允许在系统API接口中使用不超过MAX_PATH的字符长度
2.1 启用UNC Path
此方式适合用于非windows APP (在win10 1607后可以启用应用程序清单), 但动态库/早期的应用程序还需要启用UNC Path支持.
在路径前面添加 \\?\ 可使windows API 支持最大32767个字符的路径长度。
没有意外的话,就应该出意外了。
如果按只添加UNC前缀,你会发现在某些场景下如GetFileAttributesW依然会返回206错误码,这是为啥?
兼容MS-DOC FAT格式
微软系统向下兼容,在启用长路径的同时,还兼容了FAT(win8.3)路径, FAT路径长这个样子:
文件名(8字符) + .(1字符) + 扩展名(3字符) = 12字符重要
所以在windows系统中文件路径实际上有12个字节的buffer, 这12个字节用来存储FAT 路径,如果路径长度正好在MAX_PATH附近,即使没有超过MAX_PATH长度, 也会报206(长度超过限制)错误
举个例子:
- longpath1 = /path/to/name.txt, size(longpath1) = 247, CreateFileW(longpath1) // OK
- longpath2 = /path/to/name1.txt, size(longpath2) = 248, CreateFileW(longpath2) // Failed , GetLastError() = 206
综上,启用UNC path的时机:
if(path >= (MAX_PATH- 12)) {
path="\\\\?\\"+path;
}
2.2 启用系统长路径 (仅限制win10 1607版本及以上 Windows APP)
2.2.1 修改环境变量
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"LongPathsEnabled"=dword:00000001
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" `
-Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
2.2.2 更改应用程序清单
<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>
2.2 文件名组件限制
文件名组件是反斜杠之间的文件名部分。windows路径由文件名组件组成,每个路径段依然需要保证最大MAX_PATH的长度限制。
不同卷的路径段大小可能会不一致,最大大小为MAX_PATH,获取每个驱动器支持的最大长度路径段,可以用GetVolumeInformationW
BOOL GetVolumeInformationA(
[in, optional] LPCSTR lpRootPathName,
[out, optional] LPSTR lpVolumeNameBuffer,
[in] DWORD nVolumeNameSize,
[out, optional] LPDWORD lpVolumeSerialNumber,
[out, optional] LPDWORD lpMaximumComponentLength,
[out, optional] LPDWORD lpFileSystemFlags,
[out, optional] LPSTR lpFileSystemNameBuffer,
[in] DWORD nFileSystemNameSize
);
[out, optional] lpMaximumComponentLength
指向接收指定文件系统支持的文件名组件的文件名组件的最大长度(TCHAR)的变量的指针。
存储在 *lpMaximumComponentLength 指向的变量中存储的值用于指示指定的文件系统支持长名称。
例如,对于支持长名称的 FAT 文件系统,该函数存储值 255。
2.3 文件名限制
在2.2的基础上有文件名组件的长度限制,但实际上还有其他的问题,比如以下两种路径:
path1: C:\\very_longchar(240).txt // FAILED, GetLastError() = 123
path2: C:\\apath\\bpath\\cpath\\very_longchar(251) // OK , GetLastError() = 0
path3: C:\\apath\\bpath\\cpath\\very_longchar(252) // FAILED, GetLastError() = 123
上面path1 和 path2 说明文件名的长度与父目录有关系
上面path2 和 path3 说明文件长度与某些其他因素有关,(暂时还不清楚与什么有关,可以留言互相讨论)