Get-ChildItem против GetFiles против EnumerateFiles против EnumerateFileSystemEntries (что лучше?)

Я пытаюсь определить наиболее эффективный метод заполнения массива строк путями к файлам рекурсивно из заданной папки. Требуются только пути к файлам и; хотя это и не обязательно, было бы дополнительным бонусом, если бы я мог работать с полученными файлами по мере обнаружения их путей. Я использую PowerShell версии 7.3.6 в Windows 10, и у меня есть одно или несколько расширений файлов для поиска в папке со множеством подпапок и многими другими типами файлов. Я столкнулся с вопросами, представленными по ссылкам ниже, и попытался частично или полностью реализовать каждое из предложенных решений. Этот пост довольно длинный, потому что я хотел оставить как можно меньше домыслов. Мне нужны отзывы о том, как улучшить производительность фрагментов кода, включенных в этот пост, а также предложения по любым другим методам, которые могут дать более эффективные (своевременные) результаты.

Как мне заставить get-childitem фильтровать файлы нескольких типов?

https://stackoverflow.com/questions/14970692/powershell-io-directory-find-file-types-in-all-subdirectories

Совершенно очевидно, что параметр 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. Виола!

Теперь вернемся к первоначальной цели вопроса этого поста. Существуют ли другие методы достижения заявленной цели с большей эффективностью или способы повышения эффективности одного или нескольких из данных методов?

0 ответов

Другие вопросы по тегам