下面的代码从 list.txt 文件中搜索400多个数字,以查看该文件是否存在于指定文件夹路径内的任何文件中。
该脚本非常慢,并且尚未完成,因为它在运行25分钟后仍未完成。我们正在搜索的文件夹为 507 MB (532,369,408字节),其中包含 1,119个文件和 480个文件夹。非常感谢任何有助于提高搜索速度和效率的帮助。
$searchWords = (gc 'C:\temp\list.txt') -split ','
$results = @()
Foreach ($sw in $searchWords)
{
$files = gci -path 'C:\Users\david.craven\Dropbox\Asset Tagging\_SJC Warehouse_\_Project Completed_\2018\A*' -filter "*$sw*" -recurse
foreach ($file in $files)
{
$object = New-Object System.Object
$object | Add-Member -Type NoteProperty –Name SearchWord –Value $sw
$object | Add-Member -Type NoteProperty –Name FoundFile –Value $file.FullName
$results += $object
}
}
$results | Export-Csv C:\temp\output.csv -NoTypeInformation
答案 0 :(得分:6)
以下内容将大大加快您的工作速度:
如果意图确实是在文件名中查找搜索词:
$searchWords = (Get-Content 'C:\temp\list.txt') -split ','
$path = 'C:\Users\david.craven\Dropbox\Facebook Asset Tagging\_SJC Warehouse_\_Project Completed_\2018\A*'
Get-ChildItem -File -Path $path -Recurse -PipelineVariable file |
Select-Object -ExpandProperty Name |
Select-String -List -SimpleMatch -Pattern $searchWords |
Select-Object @{n='SearchWord'; e={$_.Pattern}},
@{n='FoundFile'; e={$file.FullName}} |
Export-Csv C:\temp\output.csv -NoTypeInformation
如果要在文件的内容中查找搜索词:
$searchWords = (Get-Content 'C:\temp\list.txt') -split ','
$path = 'C:\Users\david.craven\Dropbox\Facebook Asset Tagging\_SJC Warehouse_\_Project Completed_\2018\A*'
Get-ChildItem -File -Path $path -Recurse |
Select-String -SimpleMatch -Pattern $searchWords |
Select-Object @{n='SearchWord'; e={$_.Pattern}},
@{n='FoundFile'; e={$_.Path}} |
Export-Csv C:\temp\output.csv -NoTypeInformation
提高性能的关键:
使用单个命令执行搜索,方法是将 all 个搜索词传递给Select-String
。
与其使用New-Object
和Add-Member
在脚本块中构造自定义对象,不如让Select-Object
使用calculated properties在管道中直接为您构造对象
与其使用+=
迭代构建中间数组-每次在后台重新创建-而是使用单个管道将结果对象直接传递到{{ 1}}。
答案 1 :(得分:1)
因此,您发布的PowerShell代码中肯定有一些可以改进的基本内容,但可能仍然不是很快。根据您提供给我们的样本,我假设您正在寻找将文件名与单词列表进行匹配的方法。您正在遍历单词列表(400次迭代),并且在每个循环中都遍历所有1,119个文件。总共有447,600次迭代!
假设您无法减少循环中的迭代次数,那么让我们加快每次迭代的速度就可以了。 Add-Member
cmdlet真的很慢,因此通过将哈希表强制转换为[PSCustomObject]类型的加速器来切换该方法:
[PSCustomObject]@{
SearchWord = $Word
File = $File.FullName
}
此外,没有理由预先创建一个数组对象,然后将每个文件添加到其中。您可以简单地在变量中捕获foreach循环的输出:
$Results = Foreach ($Word in $Words)
{
...
所以更快的循环可能看起来像这样:
$Words = Get-Content -Path $WordList
$Files = Get-ChildItem -Path $Path -Recurse -File
$Results = Foreach ($Word in $Words)
{
foreach ($File in $Files)
{
if ($File.BaseName -match $Word)
{
[PSCustomObject]@{
SearchWord = $Word
File = $File.FullName
}
}
}
}
一种更简单的方法可能是在文件数组上使用Where-Object:
$Results = Foreach ($Word in $Words)
{
$Files | Where-Object BaseName -match $Word
}
尝试两者并测试性能。
答案 2 :(得分:0)
因此,如果加快循环速度不能满足您的需要,请尝试完全删除循环。您可以使用正则表达式并将所有单词连接在一起:
$Words = Get-Content -Path $WordList
$Files = Get-ChildItem -Path $Path -Recurse -File
$WordRegex = $Words -join '|'
$Files | Where basename -match $WordRegex