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

如何优化PowerShell中递归查找文件夹的执行性能?

优化PowerShell递归获取文件夹的性能方案

核心问题原因

Get-ChildItem -Recurse -Directory 性能低下的本质是:它会遍历目标路径下的所有项(文件+文件夹),再从中筛选出文件夹,这个过程会产生大量不必要的IO操作,在文件数量极多的目录下,耗时会急剧增加。

优化方案

直接使用.NET类库的Directory.EnumerateDirectories方法,它会仅枚举目录,无需先扫描所有文件,同时支持流式处理(边枚举边处理,不用一次性加载所有目录到内存),性能提升非常明显。

1. 基础优化:替换Get-ChildItem为Directory.EnumerateDirectories

将原代码中获取文件夹的行替换为:

# 使用.NET方法直接枚举所有子目录,跳过无权访问的目录
$enumerationOptions = [System.IO.EnumerationOptions]@{
    RecurseSubdirectories = $true
    IgnoreInaccessible = $true
}
$folders = [System.IO.Directory]::EnumerateDirectories($array[2], "*", $enumerationOptions) | ForEach-Object { Get-Item $_ }

2. 进一步优化:提前过滤目标目录

因为你只需要名称匹配^\d{4}-\d{2}$的文件夹,可以在枚举阶段直接过滤,减少后续循环处理的对象数量:

$enumerationOptions = [System.IO.EnumerationOptions]@{
    RecurseSubdirectories = $true
    IgnoreInaccessible = $true
}
$folders = [System.IO.Directory]::EnumerateDirectories($array[2], "*", $enumerationOptions) | 
    Where-Object { [System.IO.Path]::GetFileName($_) -match '^\d{4}-\d{2}$' } | 
    ForEach-Object { Get-Item $_ }

3. 同步优化文件枚举(如果$pathException也耗时)

如果获取文件的Get-ChildItem -Path $array[2] -File同样慢,也可以用Directory.EnumerateFiles替换:

$pathException = [System.IO.Directory]::EnumerateFiles($array[2], "*", [System.IO.SearchOption]::TopDirectoryOnly) | ForEach-Object { Get-Item $_ }

代码修改后的完整片段示例

foreach ($line in Get-Content ".\Exe-Purge-directories.txt") {

    $array = $line.Split("|")
    $deleteType = $array[0]
    $sdate = [int]$array[1] * -1 # 要减去的天数(负数)
    $expiredDate = (Get-Date).AddDays($sdate) # 今日加上要减去的日期

    # 优化后的文件夹枚举逻辑
    $enumerationOptions = [System.IO.EnumerationOptions]@{
        RecurseSubdirectories = $true
        IgnoreInaccessible = $true
    }
    $folders = [System.IO.Directory]::EnumerateDirectories($array[2], "*", $enumerationOptions) | 
        Where-Object { [System.IO.Path]::GetFileName($_) -match '^\d{4}-\d{2}$' } | 
        ForEach-Object { Get-Item $_ }

    # 优化后的文件枚举逻辑(如果需要)
    $pathException = [System.IO.Directory]::EnumerateFiles($array[2], "*", [System.IO.SearchOption]::TopDirectoryOnly) | ForEach-Object { Get-Item $_ }
    
    if ($deleteType.Equals("DateTimeInFolderName")) {
        foreach ($folder in $folders) {
            # 你的后续处理逻辑
            # .....
        }
    }
}

额外提示

  • 如果不需要完整的DirectoryInfo对象,直接使用枚举返回的路径字符串(跳过ForEach-Object { Get-Item $_ }),性能会进一步提升,后续处理时根据字符串操作即可。
  • IgnoreInaccessible = $true 会自动跳过无权限访问的目录,避免因权限问题中断枚举或增加额外耗时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 02:37:35