Powershell 试图在一个包含大量文件的目录中获取唯一的扩展名列表的过程非常缓慢
我试图在一个大约9TB、有几十万个文件的数据集中获得唯一扩展名的列表,以及每个扩展名的示例文件。我尝试使用get-child项,当我筛选到没有很多文件的文件夹时,它会工作,但当我筛选到有很多文件的文件夹时,它似乎永远不会启动。下面是我一直在尝试的两个例子Powershell 试图在一个包含大量文件的目录中获取唯一的扩展名列表的过程非常缓慢,powershell,Powershell,我试图在一个大约9TB、有几十万个文件的数据集中获得唯一扩展名的列表,以及每个扩展名的示例文件。我尝试使用get-child项,当我筛选到没有很多文件的文件夹时,它会工作,但当我筛选到有很多文件的文件夹时,它似乎永远不会启动。下面是我一直在尝试的两个例子 $Extensions = New-Object System.Collections.ArrayList $filesReviewed = 0 Get-ChildItem \\server\folder -Exclude 'excludeF
$Extensions = New-Object System.Collections.ArrayList
$filesReviewed = 0
Get-ChildItem \\server\folder -Exclude 'excludeFolder'| Get-ChildItem | Where-Object {$_.Name.Equals('files')} | Get-ChildItem -OutBuffer 1000 |
foreach{
Write-Progress -Activity "Files Reviewed: " -Status "$filesReviewed"
$filesReviewed++
if( $Extensions.contains($_.Extension) -eq $False) {
$Extensions.add($_.Extension)
Write-Host $_.Extension
Write-Host $Path = $_.FullName
}
}
我开始尝试使用dir,认为它可能更快,但它也有同样的问题
set-location \\server\folder
dir | dir | Where-Object {$_.Name.Equals('files')} | dir -OutBuffer 10
您可以尝试以下方法:
(获取ChildItem-路径C:\windows-文件-递归)。扩展名|选择对象-唯一
当然,将路径替换为您想要使用的路径
有关get childitem的详细信息,请参阅:
希望有帮助
Get ChildItem
检索有关文件的大量信息,而这些信息在本例中是不需要的,并且会降低您的速度。您可以尝试使用[System.IO.Directory]::GetFiles
来加快速度
$extensions=@{}
[System.IO.Directory]::GetFiles("\\server\folder", "*.*", [System.IO.SearchOption]::AllDirectories) | %
{
$extensions[[System.IO.DirectoryInfo]::new($_).Extension]++
}
$extensions | ft -a
加快代码速度有两个关键点:
- 避免使用管道,因此避免使用cmdlet
- 如果无法避免管道,请避免使用自定义脚本块(
),因为为每个输入对象执行一个脚本块非常耗时{…}
- 如果无法避免管道,请避免使用自定义脚本块(
- 通常,避免使用
,这会显著降低速度编写进度
避免使用cmdlet需要直接使用.NET framework类型。
虽然将管道(
%
,即ForEach对象
cmdlet)组合在一起会减慢速度,但在每次迭代中构建[System.IO.DirectoryInfo]
实例也会减慢速度,尽管程度较低
注意:为了简洁和简单,下面的解决方案侧重于处理给定目录的整个子树(相当于getchilditem-Recurse-File
)
性能优化的解决方案:
注意以下方面:
而不是[System.IO.Directory]::EnumerateFiles()
用于枚举文件Get ChildItem
- 使用的是
循环,而不是带有foreach
cmdlet(foreach对象的管道
)%
- 在循环内部,通过调用静态的
方法提取文件扩展名,可以避免构造不必要的对象[System.IO.Path]::GetExtension()
$seenExtensions=@{}
foreach([IO.Directory]中的文件)::枚举文件($PWD.ProviderPath,'*','AllDirectories')){
if(-not$seenExtensions.ContainsKey(($ext=[IO.Path]::GetExtension($file))){
$seenExtensions.Add($ext,$true)
[pscustomobject]@{
扩展名=$ext
示例=$file
}
}
}
上面输出一个自定义对象数组,每个对象表示一个唯一的扩展名(property.extension
)和遇到该扩展名的第一个文件的路径(.Example
)
示例输出(请注意,输出不会按扩展进行排序,但您可以简单地通过管道连接到…| Sort Object extension
):
扩展示例
--------- -------
.json C:\temp\foo.json
.txt C:\temp\sub\bar.txt
...
如果性能不是一个问题,PowerShell的cmdlet将提供更优雅的解决方案:
Get-ChildItem -File -Recurse |
Group-Object Extension |
Select @{ n='Extension'; e='Name' }, @{ n='Example'; e = { $_.Group[0].Name } }
请注意,
Group Object
通过grouping属性隐式地对输出进行排序,因此输出将按照文件扩展名的字母顺序进行排序。dir只是get childitemrobocy的别名,使用\L
“list only”选项可以使您的文件列表比PoSh中内置的任何文件都快一些。您可以告诉RC省略不需要的细节&不要显示任何进度以获得更快的速度。解析文件列表相当快。。。[grin]这是一个优雅的解决方案,但考虑到使用了选择对象-唯一性
;更一般地说,当性能很重要时,应该完全避免使用cmdlet(而不是直接使用.NET类型)。