如何提升网络资源文件存在性检查的速度
问题解决思路
一、解决网络共享目录的权限报错
报错用户名或密码不正确是因为当前进程没有访问\\server\FileStorage\files的权限,可通过以下两种方式解决:
- 提前配置系统凭据:在Windows「凭据管理器」中添加目标共享目录的用户名和密码,后续程序访问时会自动调用该凭据。
- 代码中手动添加网络连接:通过P/Invoke调用Windows API
WNetAddConnection2,在代码内传入共享目录的访问凭据,示例代码如下:
using System.Runtime.InteropServices; using System.Net; public class NetworkConnection : IDisposable { private readonly string _networkName; [DllImport("mpr.dll")] private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags); [DllImport("mpr.dll")] private static extern int WNetCancelConnection2(string name, int flags, bool force); [StructLayout(LayoutKind.Sequential)] private class NetResource { public int Scope; public int Type; public int DisplayType; public int Usage; public string LocalName; public string RemoteName; public string Comment; public string Provider; } public NetworkConnection(string networkName, NetworkCredential credentials) { _networkName = networkName; var netResource = new NetResource { Scope = 2, // RESOURCE_GLOBALNET Type = 1, // RESOURCETYPE_DISK DisplayType = 3, // RESOURCEDISPLAYTYPE_SHARE Usage = 1, // RESOURCEUSAGE_CONNECTABLE RemoteName = networkName }; var result = WNetAddConnection2(netResource, credentials.Password, credentials.UserName, 0); if (result != 0) { throw new Exception($"连接共享目录失败,错误码: {result}"); } } public void Dispose() { WNetCancelConnection2(_networkName, 0, true); } } // 使用方式 using (var connection = new NetworkConnection(@"\\server\FileStorage", new NetworkCredential("你的用户名", "你的密码"))) { // 在此执行共享目录相关操作 }
二、优化文件存在性检查的效率
原方案中File.Exists()逐个检查慢的核心原因是每个调用都会发起单独的网络请求,可通过以下思路优化:
- 批量预获取文件列表(权限解决后):用
Directory.EnumerateFiles()替代Directory.GetFiles(),前者为延迟加载,内存占用更低;将所有文件路径存入HashSet<string>,后续存在性检查可达到O(1)的时间复杂度。 - 并行检查(仅限无法解决权限问题时):若必须使用
File.Exists(),可通过Parallel.ForEach()并行处理,但需控制并发数避免对服务器造成过大压力,示例:
using System.Collections.Concurrent; var result = new ConcurrentDictionary<int, string>(); Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = 10 }, kvp => { var fullPath = Path.GetFullPath(Path.Combine(@"\\server\FileStorage\", kvp.Value)); if (File.Exists(fullPath)) { result.TryAdd(kvp.Key, fullPath); } });
- 简化路径处理逻辑:原代码中手动计算公共目录的逻辑易出错,可直接结合共享根路径与
Path.GetDirectoryName()处理,避免字符串匹配的潜在问题。
整合后的优化代码示例
假设已解决权限问题,整合后的高效实现如下:
Dictionary<int, string> files = new() { { 1, @"files\folder/5.3.231/file.exe" }, { 2, @"files\folder/5.1.1/file.exe" }, { 3, @"files\folder/4.1/sub/file55.exe" } }; // 转换为完整共享路径 var fullPathDict = files.ToDictionary(k => k.Key, v => Path.GetFullPath(Path.Combine(@"\\server\FileStorage\", v.Value))); // 提取需要检查的唯一扩展名 var extensions = fullPathDict.Values.Select(p => Path.GetExtension(p)).Distinct(); // 枚举共享目录下的目标文件,存入HashSet var existingFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase); using (var connection = new NetworkConnection(@"\\server\FileStorage", new NetworkCredential("你的用户名", "你的密码"))) { foreach (var ext in extensions) { foreach (var filePath in Directory.EnumerateFiles(@"\\server\FileStorage", $"*{ext}", SearchOption.AllDirectories)) { existingFiles.Add(Path.GetFullPath(filePath)); } } } // 筛选存在的文件 var result = fullPathDict.Where(kvp => existingFiles.Contains(kvp.Value)) .ToDictionary(k => k.Key, v => v.Value);
内容的提问来源于stack exchange,提问作者Viktor Bylbas
相关产品推荐
相关产品推荐

