如何优化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
相关产品推荐
相关产品推荐

