Рекурсивно посчитать файлы в подпапках

Я пытаюсь подсчитать файлы во всех подпапках в каталоге и отобразить их в списке.

например следующее dirtree:

TEST
    /VOL01
        file.txt
        file.pic
    /VOL02
        /VOL0201
            file.nu
            /VOL020101
                file.jpg
                file.erp
                file.gif
    /VOL03
        /VOL0301
            file.org

должно дать как выход:

PS> DirX C:TEST

Directory              Count
----------------------------
VOL01                      2
VOL02                      0
VOL02/VOL0201              1
VOL02/VOL0201/VOL020101    3
VOL03                      0
VOL03/VOL0301              1

Я начал со следующего:

Function DirX($directory)
{
    foreach ($file in Get-ChildItem $directory -Recurse)
    {
        Write-Host $file
    }
}

Теперь у меня вопрос: почему моя функция не рекурсией?

6 ответов


что-то вроде этого должно работать:

dir -recurse |  ?{ $_.PSIsContainer } | %{ Write-Host $_.FullName (dir $_.FullName | Measure-Object).Count }
  • dir -recurse перечисляет все файлы в текущем каталоге и трубах ( | ) результат в
  • ?{ $_.PSIsContainer } который фильтрует каталоги только затем снова передает результирующий список в
  • %{ Write-Host $_.FullName (dir $_.FullName | Measure-Object).Count } который является циклом foreach, который для каждого члена списка ( $ _ ) отображает полное имя и результат следующего выражения
  • (dir $_.FullName | Measure-Object).Count который предоставляет список файлов под $_.FullName путь и подсчет членов через Измерения-Объект

  • ?{ ... } - псевдоним для Where-Object

  • %{ ... } - это псевдоним для foreach

подобно решению Дэвида, это будет работать в Powershell v3.0 и не использует псевдонимы в случае, если кто-то не знаком с ними

Get-ChildItem -Directory | ForEach-Object { Write-Host $_.FullName $(Get-ChildItem $_ | Measure-Object).Count}

Ответ Дополнение

основываясь на комментарии о сохранении вашей функции и структуры цикла, я предоставляю следующее. Примечание: Я не одобряю это решение, поскольку оно уродливо, и встроенные командлеты справляются с этим очень хорошо. Однако мне нравится помогать, поэтому вот обновление вашего скрипт.

Function DirX($directory)
{
    $output = @{}

    foreach ($singleDirectory in (Get-ChildItem $directory -Recurse -Directory))
    {
        $count = 0 
        foreach($singleFile in Get-ChildItem $singleDirectory.FullName)
        {
            $count++
        }
        $output.Add($singleDirectory.FullName,$count)
    }

    $output | Out-String
}

для каждого $singleDirectory подсчитайте все файлы с помощью $count (который сбрасывается до следующего цикла sub) и выводит каждый поиск в хэш-таблицу. В конце выведите hashtable в виде строки. В вашем вопросе вы выглядели так, как будто вам нужен вывод объекта вместо прямого текста.


Ну, то, как вы это делаете все Get-ChildItem командлет должен быть завершен до foreach цикл может начать итерацию. Ты уверен, что ждешь достаточно долго? Если вы запустите это против очень больших каталогов (например, C:), это займет довольно много времени.

Edit: видел, что вы просили ранее способ заставить вашу функцию делать то, что вы просите, вот вы идете.

Function DirX($directory)
{
    foreach ($file in Get-ChildItem $directory -Recurse -Directory )
    {
        [pscustomobject] @{
        'Directory' = $File.FullName
        'Count' = (GCI $File.FullName -Recurse).Count
        }
    }
}
DirX D:\

цикл foreach только получает каталоги, так как это все, о чем мы заботимся, а затем внутри цикл пользовательский объект создается для каждой итерации с полным путем к папке и количеством элементов внутри папки.

кроме того, обратите внимание, что это будет работать только в PowerShell 3.0 или новее, поскольку -directory параметр не существовал в 2.0


моя версия-немного чище и сбрасывает содержимое в файл

Оригинал - рекурсивно подсчитывать файлы в подпапках

Вторая Составляющая - подсчет элементов в папке с PowerShell

$FOLDER_ROOT = "F:\"
$OUTPUT_LOCATION = "F:DLS\OUT.txt"
Function DirX($directory)
{
    Remove-Item $OUTPUT_LOCATION

    foreach ($singleDirectory in (Get-ChildItem $directory -Recurse -Directory))
    {
        $count = Get-ChildItem $singleDirectory.FullName -File | Measure-Object | %{$_.Count}
        $summary = $singleDirectory.FullName+"    "+$count+"    "+$singleDirectory.LastAccessTime
        Add-Content $OUTPUT_LOCATION $summary
    }
}
DirX($FOLDER_ROOT)

Я немного изменил решение Дэвида Брабанта, чтобы оценить результат:

$FileCounter=gci "$BaseDir" -recurse |  ?{ $_.PSIsContainer } | %{ (gci "$($_.FullName)" | Measure-Object).Count }
Write-Host "File Count=$FileCounter"
If($FileCounter -gt 0) {
  ... take some action...
}

Get-ChildItem $rootFolder `
    -Recurse -Directory | 
        Select-Object `
            FullName, `
            @{Name="FileCount";Expression={(Get-ChildItem $_ -File | 
        Measure-Object).Count }}