Get-ChildItem против GetFiles против EnumerateFiles против EnumerateFileSystemEntries (что лучше?)
Я пытаюсь определить наиболее эффективный метод заполнения массива строк путями к файлам рекурсивно из заданной папки. Требуются только пути к файлам и; хотя это и не обязательно, было бы дополнительным бонусом, если бы я мог работать с полученными файлами по мере обнаружения их путей. Я использую PowerShell версии 7.3.6 в Windows 10, и у меня есть одно или несколько расширений файлов для поиска в папке со множеством подпапок и многими другими типами файлов. Я столкнулся с вопросами, представленными по ссылкам ниже, и попытался частично или полностью реализовать каждое из предложенных решений. Этот пост довольно длинный, потому что я хотел оставить как можно меньше домыслов. Мне нужны отзывы о том, как улучшить производительность фрагментов кода, включенных в этот пост, а также предложения по любым другим методам, которые могут дать более эффективные (своевременные) результаты.
Как мне заставить get-childitem фильтровать файлы нескольких типов?
Совершенно очевидно, что параметр Get-ChildItem -Filter не принимает множественные критерии, что является обязательным в моем случае использования. Поэтому одним из потенциальных решений является Get-ChildItem с параметрами -Include и -Exclude, которое реализовано следующим образом:
[string]$SourcePath = "H:\Duplicate File Work\"
[string[]]$IncludeFilter = $null
[string[]]$FilePathCollection = $null
$IncludeFilter += "*.doc"
$IncludeFilter += "*.xls"
$IncludeFilter += "*.ppt"
$StopWatch = [System.Diagnostics.Stopwatch]::New()
$StopWatch.Start()
$FilePathCollection = Get-ChildItem -Path $SourcePath -Include $IncludeFilter -Recurse
Write-Host $FilePathCollection.Count
$StopWatch.Stop()
$StopWatch.Elapsed
Приведенный выше код выдал 22853 результата примерно за 4 минуты:27 секунд и не позволил мне работать с каждым файлом по мере его обнаружения, поскольку массив строк должен быть полностью заполнен Get-ChildItem, прежде чем его можно будет использовать. Другое потенциальное решение — GetFiles, которое реализовано следующим образом:
[string]$SourcePath = "H:\Duplicate File Work\"
[string[]]$IncludeFilter = $null
[string[]]$FilePathCollection = $null
$IncludeFilter += "*.doc"
$IncludeFilter += "*.xls"
$IncludeFilter += "*.ppt"
$StopWatch = [System.Diagnostics.Stopwatch]::New()
$StopWatch.Start()
foreach ($Filter in $IncludeFilter) {
foreach ($File in [IO.Directory]::GetFiles($SourcePath, $Filter, "AllDirectories")) {
$FileAttributes = (Get-ItemProperty -Path $File).Attributes -split ", "
if ($FileAttributes -match "Hidden") {
Continue
}
else {
$FilePathCollection += $File
}
}
}
Write-Host $FilePathCollection.Count
$StopWatch.Stop()
$StopWatch.Elapsed
Приведенный выше код дал 22853 результата; то же число, что и Get-ChildItem, примерно за 6 минут:6 секунд, что позволило мне работать с каждым файлом по мере его обнаружения. Обратите внимание на добавление блока if/else, позволяющего фильтровать скрытые файлы по мере их обнаружения. EnumerateFiles и EnumerateFileSystemEntries дали тот же результат, что и GetFiles, за 6 минут:49 секунд и 6 минут:42 секунды соответственно. Командлет Get-ChildItem не нашел скрытые файлы, как это сделали GetFiles, EnumerateFiles и EnumerateFileSystemEntries. Очевидным выбором с точки зрения эффективности (своевременности) является Get-ChildItem; однако этот метод не позволяет выполнять работу с файлами по мере их обнаружения. Чтобы убедиться, что 22853 файла, найденные командами Get-ChildItem и GetFiles, являются одними и теми же 22853 файлами, был использован следующий код:
[string]$SourcePath = "H:\Duplicate File Work\"
[string[]]$IncludeFilter = $null
[string[]]$FilePathCollection1 = $null
[string[]]$FilePathCollection2 = $null
[system.object]$CompareObjects = $null
[system.object]$StopWatch = [System.Diagnostics.Stopwatch]::New()
$IncludeFilter += "*.doc"
$IncludeFilter += "*.xls"
$IncludeFilter += "*.ppt"
$StopWatch.Start()
foreach ($Filter in $IncludeFilter) {
foreach ($File in [IO.Directory]::GetFiles($SourcePath, $Filter, "AllDirectories")) {
$FileAttributes = (Get-ItemProperty -Path $File).Attributes -split ", "
if ($FileAttributes -match "Hidden") {
Continue
}
else {
$FilePathCollection1 += $File
}
}
}
Write-Host $FilePathCollection1.Count
$StopWatch.Stop()
$StopWatch.Elapsed
$StopWatch.Reset()
$StopWatch.Start()
foreach ($File in Get-ChildItem -Path $SourcePath -Include $IncludeFilter -Recurse) {
$FilePathCollection2 += $File
}
Write-Host $FilePathCollection2.Count
$StopWatch.Stop()
$StopWatch.Elapsed
$CompareObjects = Compare-Object -ReferenceObject $FilePathCollection1 -DifferenceObject $FilePathCollection2
$CompareObjects | Out-GridView
Проверка результатов Compare-Object (нет) не выявила различий между файлами, найденными Get-ChildItem, и файлами, найденными GetFiles. Виола!
Теперь вернемся к первоначальной цели вопроса этого поста. Существуют ли другие методы достижения заявленной цели с большей эффективностью или способы повышения эффективности одного или нескольких из данных методов?