如何提升C#中批量获取文件SID与NTAccount的速度?
优化大量文件获取NTAccount和SID的性能方案
针对36万级文件获取所有者信息时的性能瓶颈,可通过以下几种优化方案大幅缩短耗时:
1. 合并重复的所有者获取操作
原代码两次调用GetOwner分别获取SID和NTAccount,实际上只需获取一次SID,再通过Translate方法转换为NTAccount,减少一次系统IO交互:
var directorySecurity = Directory.GetAccessControl(directoryPath); var sid = directorySecurity.GetOwner(typeof(System.Security.Principal.SecurityIdentifier)) as System.Security.Principal.SecurityIdentifier; if (sid != null) { ownerSid = sid.Value; var ntAccount = sid.Translate(typeof(System.Security.Principal.NTAccount)) as System.Security.Principal.NTAccount; ownerName = ntAccount?.Value; }
2. 缓存SID与NTAccount的映射关系
大量文件往往属于同一所有者,重复解析SID到账户名会浪费资源。用字典缓存已解析的映射,避免重复转换:
// 静态缓存,全局复用 private static readonly Dictionary<string, string> _sidAccountCache = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // 处理单个文件时 var sid = directorySecurity.GetOwner(typeof(System.Security.Principal.SecurityIdentifier)) as System.Security.Principal.SecurityIdentifier; if (sid != null) { ownerSid = sid.Value; // 优先从缓存读取 if (!_sidAccountCache.TryGetValue(ownerSid, out ownerName)) { var ntAccount = sid.Translate(typeof(System.Security.Principal.NTAccount)) as System.Security.Principal.NTAccount; ownerName = ntAccount?.Value; _sidAccountCache[ownerSid] = ownerName; } }
3. 仅获取必要的安全信息
默认Directory.GetAccessControl会读取全部安全数据(所有者、组、权限列表等),但我们只需要所有者信息,指定AccessControlSections.Owner可减少IO传输的数据量:
// 仅获取所有者相关的安全信息 var directorySecurity = Directory.GetAccessControl(directoryPath, AccessControlSections.Owner);
4. 并行处理文件列表
文件操作属于IO密集型任务,利用多核CPU并行处理可大幅压缩总耗时,注意控制并行度避免IO过载:
// 假设filePaths是待处理的文件路径列表 Parallel.ForEach(filePaths, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 }, filePath => { // 这里放入单个文件的处理逻辑(包含上述优化) });
5. 直接调用Win32 API替代托管方法
托管的Directory.GetAccessControl封装了额外的检查逻辑,直接调用Win32的GetNamedSecurityInfo可减少封装开销,适合超大量文件场景:
using System.Runtime.InteropServices; [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint GetNamedSecurityInfo( string pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, out IntPtr pSidOwner, out IntPtr pSidGroup, out IntPtr pDacl, out IntPtr pSacl, out IntPtr pSecurityDescriptor); private enum SE_OBJECT_TYPE { SE_FILE_OBJECT = 1 } private enum SECURITY_INFORMATION { OWNER_SECURITY_INFORMATION = 0x00000001 } // 使用示例 uint result = GetNamedSecurityInfo( filePath, SE_OBJECT_TYPE.SE_FILE_OBJECT, SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION, out IntPtr sidPtr, out _, out _, out _, out _); if (result == 0) // 调用成功 { var sid = new System.Security.Principal.SecurityIdentifier(sidPtr); ownerSid = sid.Value; // 结合缓存处理NTAccount转换 Marshal.FreeHGlobal(sidPtr); // 释放非托管内存 }
以上方案可组合使用,建议优先采用前三种轻量优化,若性能仍不达标再尝试并行或Win32 API方案。
内容的提问来源于stack exchange,提问作者user23329034
相关产品推荐
相关产品推荐

