C#获取路径超260字符的文件/目录安全信息问题
解决超长路径文件/目录的安全信息获取问题
我来帮你搞定这个头疼的超长路径安全信息获取问题!你提到的遍历方法能处理长路径但拿不到权限数据,核心是常规安全API默认不支持超长路径,下面给你几个实用的落地方案:
方案1:直接调用支持长路径的Win32 P/Invoke API
Win32的GetNamedSecurityInfoW原生支持带\\?\前缀的超长路径,我们可以把它封装成C#方法来用。这里给你一段可直接复用的代码:
using System; using System.Runtime.InteropServices; using System.Security.AccessControl; public static class LongPathSecurityHelper { // Win32常量定义 private const int ERROR_SUCCESS = 0; private const int OWNER_SECURITY_INFORMATION = 0x00000001; private const int DACL_SECURITY_INFORMATION = 0x00000004; private const uint SE_FILE_OBJECT = 1; // 导入GetNamedSecurityInfoW API [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern uint GetNamedSecurityInfoW( string pObjectName, uint ObjectType, uint SecurityInfo, out IntPtr ppsidOwner, out IntPtr ppsidGroup, out IntPtr ppDacl, out IntPtr ppSacl, out IntPtr ppSecurityDescriptor); // 导入内存释放API [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr LocalFree(IntPtr hMem); // 获取文件/目录的安全信息 public static FileSecurity GetFileOrDirectorySecurity(string path) { // 处理超长路径:自动添加\\?\前缀(UNC路径要转成\\?\UNC\server\share格式) string longPath = path.StartsWith(@"\\?\") ? path : path.StartsWith(@"\") ? @"\\?\UNC\" + path.TrimStart('\\').Replace('\\', '/') : @"\\?\" + path; IntPtr ownerSid, groupSid, dacl, sacl, securityDescriptor; uint result = GetNamedSecurityInfoW( longPath, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, out ownerSid, out groupSid, out dacl, out sacl, out securityDescriptor); if (result != ERROR_SUCCESS) { throw new System.ComponentModel.Win32Exception((int)result); } try { // 将Win32安全描述符转换为.NET的FileSecurity对象 FileSecurity security = new FileSecurity(); byte[] sdBytes = new byte[Marshal.ReadInt32(securityDescriptor)]; Marshal.Copy(securityDescriptor, sdBytes, 0, sdBytes.Length); security.SetSecurityDescriptorBinaryForm(sdBytes); return security; } finally { // 释放Win32分配的内存,避免泄漏 LocalFree(securityDescriptor); } } }
使用时直接调用LongPathSecurityHelper.GetFileOrDirectorySecurity("你的超长路径"),返回的FileSecurity对象里就能拿到所有者、访问权限列表等所有安全信息。
方案2:启用.NET原生长路径支持(.NET Framework 4.6.2+/.NET Core 2.0+)
如果你的项目用的是支持长路径的.NET版本,先通过配置开启长路径支持,就能直接用原生的安全API了:
.NET Framework 配置
在app.config的<runtime>节点里添加:
<runtime> <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" /> </runtime>
.NET Core/.NET 5+ 配置
在runtimeconfig.json里添加:
{ "runtimeOptions": { "configProperties": { "System.IO.UseLegacyPathHandling": false, "System.IO.BlockLongPaths": false } } }
配置完成后,你可以用Directory.EnumerateFileSystemEntries遍历超长路径,然后对每个路径调用File.GetAccessControl或Directory.GetAccessControl。不过要注意,遇到极端长路径时,还是手动加上\\?\前缀更稳妥。
方案3:与现有遍历代码集成
如果你已经在用Kim Hamilton的遍历代码,只需要在遍历到每个文件/目录时,把路径传入上面的GetFileOrDirectorySecurity方法即可,完美适配现有逻辑。
关键注意事项
- 权限要求:程序需要有读取目标文件/目录安全信息的权限,部分场景下可能需要管理员权限。
- UNC路径处理:共享目录的超长路径要转成
\\?\UNC\server\share\...格式,不能直接加\\?\前缀。 - 内存管理:调用Win32 API后一定要释放分配的内存,上面的代码已经帮你处理了,但自己写P/Invoke时别忘这点。
内容的提问来源于stack exchange,提问作者Merin Nakarmi




