You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提升网络资源文件存在性检查的速度

问题解决思路

一、解决网络共享目录的权限报错

报错用户名或密码不正确是因为当前进程没有访问\\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()逐个检查慢的核心原因是每个调用都会发起单独的网络请求,可通过以下思路优化:

  1. 批量预获取文件列表(权限解决后):用Directory.EnumerateFiles()替代Directory.GetFiles(),前者为延迟加载,内存占用更低;将所有文件路径存入HashSet<string>,后续存在性检查可达到O(1)的时间复杂度。
  2. 并行检查(仅限无法解决权限问题时):若必须使用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);
    }
});
  1. 简化路径处理逻辑:原代码中手动计算公共目录的逻辑易出错,可直接结合共享根路径与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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 08:53:19