Вывести список всех папок и подпапок в заданной структуре с размером файла - PullRequest
0 голосов
/ 21 января 2019

Я пытаюсь перечислить структуру папок на диске и размер каждой папки.

У меня есть структура папок, теперь мне просто нужно вывести размер каждой папки.

В соответствии с https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/dir нет флага для отображения размера файла - только его скрытие.Я предполагаю, что я пошел по неверному пути, но любая помощь приветствуется.

Это то, что я получил до сих пор:

dir /s /b /o:n /a:d > "C:\folderlist.txt"

Ожидаемый результат:

C:\WINDOWS\system32\downlevel 400mb
C:\WINDOWS\system32\drivers 100mb
C:\WINDOWS\system32\DriverState 4kb
C:\WINDOWS\system32\DriverStore 1kb
C:\WINDOWS\system32\DRVSTORE 1gb

Аббревиатура для размера файла, т.е. (мб, кб, гб, тб) не имеет значения.Пока он показывает размер папки некоторым количественным образом.

Альтернатива Powershell также приветствуется.

Ответы [ 3 ]

0 голосов
/ 21 января 2019

Вот пакетный скрипт, который перечисляет все каталоги в данном корневом каталоге и их размеры. В качестве первого аргумента командной строки укажите корневой каталог; если опущен, используется текущий каталог. Это код:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_ROOT=%~1" & if not defined _ROOT set "_ROOT=."

rem // Change into the given root directory:
pushd "%_ROOT%" && (
    rem // Walk through all immediate sub-directories:
    for /F "delims= eol=|" %%D in ('dir /B /A:D-H "*"') do (
        rem // Initialise variable holding size of sub-directory:
        set "SIZE=0"
        rem // Process sub-directory in a sub-soutine:
        set "ITEM=%%~D" & call :PROCESS SIZE "%%ITEM%%"
        rem // Display size of sub-directory:
        call set "SIZE=              %%SIZE%%"
        set "ITEM=%%~fD" & call echo %%SIZE:~-14%%  "%%ITEM%%"
    )
    popd
)

endlocal
exit /B


:PROCESS
    rem /* Change into the given directory; use short names to avoid trouble with
    rem    extremely long and/or deep paths (remember the limit is 260 characters): */
    pushd "%~s2" && (
        rem /* Walk through all files in the directory; instead of a normal `for` loop,
        rem    `dir` together with a `for /F` loop is used, because `for` would ignore
        rem    hidden files; with `dir` you can choose the attributes and therefore
        rem    ensure that all files are returned: */
        for /F "delims= eol=|" %%F in ('2^> nul dir /B /A:-D "*"') do (
            rem // Sum up the file sizes in a sub-routine:
            call :SUM SIZE "%%SIZE%%" "%%~zF"
        )
        rem /* Walk through all sub-directories; instead of a normal `for` loop, `dir`
        rem    together with a `for /F` loop is used, because `for` would ignore hidden
        rem    sub-directories; with `dir` you can choose the attributes and therefore
        rem    ensure that all sub-directories are returned: */
        for /F "delims= eol=|" %%D in ('2^> nul dir /B /A:D "*"') do (
            rem // Call this sub-routine recursively to process sub-directories:
            set "ITEM=%%~D" & call :PROCESS SIZE "%%ITEM%%"
        )
        popd
    )
    rem // Return resulting directory size:
    set "%~1=%SIZE%"
    exit /B

:SUM
    rem // Split provided numbers into ones and billions:
    set "ENA1=%~2" & set "ENA2=%~3"
    set "GIG1=%ENA1:~,-9%" & set "ENA1=%ENA1:~-9%"
    set "GIG2=%ENA2:~,-9%" & set "ENA2=%ENA2:~-9%"
    rem /* Sum up the ones, disregard leading zeros, which would let numbers be
    rem    interpreted as octal ones: */
    for /F "tokens=* delims=0" %%M in ("0%ENA1%") do (
        for /F "tokens=* delims=0" %%N in ("0%ENA2%") do (
            set /A "ENA=%%M+%%N+0"
        )
    )
    rem // Sum up the billions, regard the carry from the ones:
    set "GIG=%ENA:~,-9%" & set /A "GIG1+=0, GIG2+=0, GIG+=GIG1+GIG2"
    rem // Join resulting billions and ones to the finally resulting number:
    set "ENA=000000000%ENA%"
    for /F "tokens=* delims=0" %%K in ("%GIG%%ENA:~-9%") do set "%~1=%%K"
    exit /B

Пример вызова (при условии, что скрипт называется list_folders.bat):

list_folders.bat "D:\Root"

Пример вывода:

        442368  "D:\Root\Data"
     101685022  "D:\Root\More"
       5441536  "D:\Root\Test"
0 голосов
/ 21 января 2019

A Решение PowerShell , основанное на полезном ответе montonero и улучшающее следующие аспекты:

  • управление глубиной рекурсии
  • улучшенная производительность
  • улучшенная интеграция с другими командлетами для комбинируемой функциональности

Примеры вызовов на основе функции Get-DirectorySize, определенной ниже:

# Get the size of the current directory (only).
Get-DirectorySize

# As requested by the OP:
# Recursively report the sizes of all subdirectories in the current directory.
Get-DirectorySize -Recurse -ExcludeSelf

# Get the size of all child directories and sort them by size, from largest
# to smallest, showing only the 5 largest ones:
Get-DirectorySize -Depth 1 -ExcludeSelf |
  Sort-Object Size -Descending |
    Select-Object -First 5

Пример вывода изпоследняя команда:

FullName                           FriendlySize       Size
--------                           ------------       ----
C:\Users\jdoe\AppData                3.27gb     3514782772
C:\Users\jdoe\Desktop              801.40mb      840326199
C:\Users\jdoe\.nuget               778.97mb      816814396
C:\Users\jdoe\.vscode              449.12mb      470931418
C:\Users\jdoe\Projects             104.07mb      109127742

Обратите внимание, что свойство .FriendlySize содержит понятное, автоматически масштабируемое string представление размера, тогда как .Size - это число ([long]), содержащеефактическое число байтов, которое облегчает дальнейшие программные процессы.

Примечание. Добавление свойств к объектам вывода, которые облегчают дружественное отображение , выполняется только для удобства реализации.Надлежащим способом Powershell было бы вместо этого определить инструкции форматирования на основе типа выходного объекта - см. документы .

Предостережения (применимо и к связанному ответу):

  • Сообщаются только логические размеры, то есть фактические байты, необходимые для файла data , который отличается от размера надиск , который обычно больше из-за файлов, занимающих блоки фиксированного размера;и наоборот, сжатые и разреженные файлы занимают меньше дискового пространства.

  • Реализация рекурсии (с -Recurse и / или -Depth) составляет неэффективно , поскольку поддерево каждого обнаруженного каталога сканируется полностью;В некоторой степени этому помогает кэш файловой системы.


Get-DirectorySize исходный код

Примечание. Требуется Windows PowerShell v3 +;также совместим с PowerShell Core .

function Get-DirectorySize
{

  param(
    [Parameter(ValueFromPipeline)] [Alias('PSPath')]
    [string] $LiteralPath = '.',
    [switch] $Recurse,
    [switch] $ExcludeSelf,
    [int] $Depth = -1,
    [int] $__ThisDepth = 0 # internal use only
  )

  process {

    # Resolve to a full filesystem path, if necessary
    $fullName = if ($__ThisDepth) { $LiteralPath } else { Convert-Path -ErrorAction Stop -LiteralPath $LiteralPath }

    if ($ExcludeSelf) { # Exclude the input dir. itself; implies -Recurse

      $Recurse = $True
      $ExcludeSelf = $False

    } else { # Process this dir.

      # Calculate this dir's total logical size.
      # Note: [System.IO.DirectoryInfo].EnumerateFiles() would be faster, 
      # but cannot handle inaccessible directories.
      $size = [Linq.Enumerable]::Sum(
        [long[]] (Get-ChildItem -Force -Recurse -File -LiteralPath $fullName).ForEach('Length')
      )

      # Create a friendly representation of the size.
      $decimalPlaces = 2
      $padWidth = 8
      $scaledSize = switch ([double] $size) {
        {$_ -ge 1tb } { $_ / 1tb; $suffix='tb'; break }
        {$_ -ge 1gb } { $_ / 1gb; $suffix='gb'; break }
        {$_ -ge 1mb } { $_ / 1mb; $suffix='mb'; break }
        {$_ -ge 1kb } { $_ / 1kb; $suffix='kb'; break }
        default       { $_; $suffix='b'; $decimalPlaces = 0; break }
      }

      # Construct and output an object representing the dir. at hand.
      [pscustomobject] @{
        FullName = $fullName
        FriendlySize = ("{0:N${decimalPlaces}}${suffix}" -f $scaledSize).PadLeft($padWidth, ' ')
        Size = $size
      }

    }

    # Recurse, if requested.
    if ($Recurse -or $Depth -ge 1) {
      if ($Depth -lt 0 -or (++$__ThisDepth) -le $Depth) {
        # Note: This top-down recursion is inefficient, because any given directory's
        #       subtree is processed in full.
        Get-ChildItem -Force -Directory -LiteralPath $fullName |
          ForEach-Object { Get-DirectorySize -LiteralPath $_.FullName -Recurse -Depth $Depth -__ThisDepth $__ThisDepth }
      }
    }

  }

}

Вот справка на основе комментариев для функции;если вы добавите функцию, скажем, к вашему $PROFILE, поместите справку непосредственно над функцией или просто внутри тела функции, чтобы получить поддержку для -? и автоматическую интеграцию с Get-Help.

<#
.SYNOPSIS
Gets the logical size of directories in bytes.

.DESCRIPTION
Given a literal directory path, output that directory's logical size, i.e.,
the sum of all files contained in the directory, including hidden ones.

NOTE: 
* The logical size is distinct from the size on disk, given that files
  are stored in fixed-size blocks. Furthermore, files can be compressed
  or sparse.
  Thus, the size of regular files on disk is typically greater than
  their logical size; conversely, compressed and sparse files require less
  disk space.
  Finally, the list of child items maintained by the filesystem for each 
  directory requires disk space too.

* Wildcard expressions aren't directly supported, but you may pipe in
  Output from Get-ChildItem / Get-Item; if files rather than directotries 
  happen to be among the input objects, their size is reported as-is.

CAVEATS:
 * Can take a long time to run with large directory trees, especially with
   -Recurse.
* Recursion is implemented inefficently.

.PARAMETER LiteralPath
The literal path of a directory. May be provided via the pipeline.

.PARAMETER Recurse
Calculates the logical size not only of the input directory itself, but of
all subdirectories in its subtree too.
To limit the recursion depth, use -Depth.

.PARAMETER Depth
Limits the recursion depth to the specified number of levels. Implies -Recurse.
Note that 0 means no recursion. Use just -Recurse in order not to limit the
recursion.

.PARAMETER ExcludeSelf
Excludes the target directory itself from the size calculation.
Implies -Recurse. Since -Depth implies -Recurse, you could use -ExcludeSelf
-Depth 1 to report only the sizes of the immediate subdirectories.

.OUTPUTS
[pscustomobject] instances with properties FullName, Size, and FriendlySize.

.EXAMPLE
Get-DirectorySize

Gets the logical size of the current directory.

.EXAMPLE
Get-DirectorySize -Recurse

Gets the logical size of the current directory and all its subdirectories.

.EXAMPLE
Get-DirectorySize /path/to -ExcludeSelf -Depth 1 | Sort-Object Size

Gets the logical size of all child directories in /path/to without including
/path/to itself, and sorts the result by size (largest last).
#>
0 голосов
/ 21 января 2019

Вы не можете получить размеры папок с dir. Вам нужно будет индивидуально посчитать размер для каждой папки рекурсивно. Есть несколько рабочих примеров Powershell. Это довольно мило https://md3v.com/getting-a-folder-tree-size-with-powershell:

function tree($startFolder)
{
   $colItems = Get-ChildItem $startFolder | Where-Object {$_.PSIsContainer -eq $true} | Sort-Object
   foreach ($i in $colItems)
   {
       $subFolderItems = Get-ChildItem $i.FullName -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Measure-Object -property Length -sum | Select-Object Sum
       $i.FullName + " -- " + "{0:N2}" -f ($subFolderItems.sum / 1MB) + " MB"
       tree $i.FullName
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...