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

如何优化含多子目录的网络位置文件搜索效率?

网络目录下大数量.gz文件按时间过滤的优化方案

核心问题分析

当前代码的主要性能瓶颈:

  • Directory.GetFiles会一次性加载所有匹配*.gz的文件路径到内存,在网络目录下大量文件的场景下,既占用内存又等待时间长
  • 每次Where过滤时重复创建FileInfo,每个实例都会发起一次网络请求获取文件属性,重复IO导致耗时剧增

优化方案

1. 改用流式遍历:Directory.EnumerateFiles

EnumerateFiles是延迟加载模式,会逐个返回匹配的文件路径,无需一次性加载所有结果,大幅降低内存占用,同时能提前开始过滤处理,减少等待时间。同时每个文件路径只创建一次FileInfo,避免重复网络请求:

private void PollFolder(string sourceDir)
{
    try
    {
        var start = DateTime.Now.AddMonths(-5);
        var end = DateTime.Now;

        var filesFromToolDir = Directory.EnumerateFiles(sourceDir, "*.gz", SearchOption.AllDirectories)
                .Select(path => new FileInfo(path)) // 仅创建一次FileInfo
                .Where(file => file.CreationTime >= start && file.CreationTime <= end)
                .ToArray();
    }
    catch (Exception ex)
    {
        // 建议添加日志记录异常,避免无感知失败
        // Logger.Error(ex, "Polling network folder failed");
    }
}

2. 并行遍历(需控制并发度)

在网络带宽允许的前提下,可以用并行遍历提升效率,但需限制并发数,避免因过多并发请求导致网络共享服务限流或响应变慢:

private void PollFolder(string sourceDir)
{
    try
    {
        var start = DateTime.Now.AddMonths(-5);
        var end = DateTime.Now;
        var resultFiles = new List<FileInfo>();
        // 控制并发数,建议根据网络环境调整(如2-8)
        var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 4 };

        Parallel.ForEach(Directory.EnumerateFiles(sourceDir, "*.gz", SearchOption.AllDirectories), parallelOptions, path =>
        {
            var fileInfo = new FileInfo(path);
            if (fileInfo.CreationTime >= start && fileInfo.CreationTime <= end)
            {
                lock (resultFiles) // 线程安全的添加结果
                {
                    resultFiles.Add(fileInfo);
                }
            }
        });

        var filesFromToolDir = resultFiles.ToArray();
    }
    catch (Exception ex)
    {
        // 异常处理逻辑
    }
}

3. 利用Windows索引服务(Windows环境专属)

如果是Windows系统,且目标网络共享已开启Windows搜索索引,可以直接查询索引获取结果,无需遍历所有目录,速度会大幅提升。可以通过WMI实现:

using System.Management;

private void PollFolderWithWindowsSearch(string sourceDir)
{
    try
    {
        var start = DateTime.Now.AddMonths(-5);
        var end = DateTime.Now;
        // 格式化WMI要求的日期格式:yyyyMMddHHmmss.ffffff
        var startStr = start.ToString("yyyyMMddHHmmss.ffffff");
        var endStr = end.ToString("yyyyMMddHHmmss.ffffff");
        // 转义路径中的反斜杠
        var escapedPath = sourceDir.Replace("\\", "\\\\");
        // WMI查询语句
        var query = $"SELECT Name FROM CIM_DataFile WHERE Extension='gz' " +
                   $"AND CreationDate >= '{startStr}' AND CreationDate <= '{endStr}' " +
                   $"AND Path LIKE '{escapedPath}\\\\%'";

        var resultFiles = new List<string>();
        using var searcher = new ManagementObjectSearcher(query);
        foreach (var obj in searcher.Get())
        {
            resultFiles.Add(obj["Name"].ToString());
        }

        // 如需FileInfo可后续转换
        var filesFromToolDir = resultFiles.Select(path => new FileInfo(path)).ToArray();
    }
    catch (Exception ex)
    {
        // 异常处理逻辑
    }
}

4. 增量扫描(定期任务场景)

如果是定期执行的扫描任务,可以记录上次扫描的时间戳,仅扫描目录中修改时间晚于上次扫描时间的文件,或者结合目录的LastWriteTime跳过未修改的子目录,减少不必要的遍历。


内容的提问来源于stack exchange,提问作者Datboydozy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 14:25:15