【问题标题】:Listing directories with name and size列出目录的名称和大小
【发布时间】:2020-05-16 07:21:13
【问题描述】:

我想列出具有全名、大小、LastWriteTime 的目录并递归到第三级。

Get-ChildItem -Depth 3 |
    Where-Object {
        $_.PSIsContainer
        } |
    ForEach-Object {
        $_.FullName + ";" + "{0:N2}" -f ((Get-ChildItem $_ -Recurse |
            Measure-Object Length -Sum -ErrorAction SilentlyContinue).Sum / 1MB) + " MB"+";"+ $_.LastWriteTime
        }

但大小仅针对第一级目录进行测量。

输出是:

C:\folder1\folder2 ; 487,69 MB ; 30.01.2020 17:58:45
C:\folder1\folder2\folder3 ; 0,00 MB ; 30.01.2020 17:59:34
C:\folder1\folder2\folder3\folder4 ; 0,00 MB ; 30.01.2020 17:59:37

但是应该是这样的,因为我在每个文件夹中都放了同一个文件:

C:\folder1\folder2 ; 1463,07 MB ; 30.01.2020 17:58:45
C:\folder1\folder2\folder3 ; 975,38 MB ; 30.01.2020 17:59:34
C:\folder1\folder2\folder3\folder4 ; 487,69 MB ; 30.01.2020 17:59:37

【问题讨论】:

  • 因此,您想要获取 Get-ChildItem 的三个子树中的所有目录,然后想要遍历其中的所有文件以获取长度,然后报告 3 个深层目录中的每一个及其尺寸?
  • 是的,没错。它适用于 C:\directory1,但是当涉及到第二和第三级(C:\directory1\directory2 和 C:\directory1\directory2\directory3)时,Size 的值将始终为 0.00 MB。跨度>
  • @MarcJefferson5 - 您的 desired 结果显示所有子目录的大小相同。你真的拥有folder4中的所有文件吗?
  • 你是对的。我更正了。
  • @MarcJefferson5 - 太好了!谢谢... [咧嘴笑]

标签: powershell directory size get-childitem


【解决方案1】:

这会输出目录的FullNameSizeLastWriteTime。请注意,size 为空则不输出任何内容:

Get-ChildItem -Depth 3 | 
    Where-Object { $_.PSIsContainer} |
    foreach{
        $size = "{0:N2}" -f ((Get-ChildItem $_ -Recurse | 
            Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum / 1MB)

        if ($size){
            Write-Host $_.FullName  ";"  $size "MB" ";" $_.LastWriteTime
        }
    }

让我们知道你的进展。

更新

在更新您的问题后,请尝试以下代码:

Get-ChildItem -Depth 3 | 
    Where-Object { $_.PSIsContainer} |
    foreach{
        $folders = Get-ChildItem $_.FullName -Recurse

        [int]$totalSize = 0
        
        foreach ($folder in $folders){
            $totalSize += (Get-ItemProperty -Path $folder.FullName -Name Length -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Length)
        }

        if ($totalSize){
            Write-Host $_.FullName  ";"  $totalSize ";" $_.LastWriteTime
        }
    }

它可能可以清理,我只是想看看这是否如你所愿:)

【讨论】:

  • 它仍然没有正确输出子树的大小。
  • C:\folder1\folder2 ; 487,69 MB ; 30.01.2020 17:58:45 C:\folder1\folder2\folder3 ; 0,00 MB ; 30.01.2020 17:59:34 C:\folder1\folder2\folder3\folder4 ; 0,00 MB ; 30.01.2020 17:59:37
  • 能否请您更新您的问题,用您希望与您目前得到的东西相处?
  • 是的,更新后的代码正在按照我的意愿运行。乍一看,这些值似乎不正确。
【解决方案2】:

您要做的是检查每个子目录的内容,并将其添加到其父目录中。然后那个父母必须告诉它是超级父母,那个祖父母=>曾祖父母等等。

每个文件都必须通知每个祖先它的大小,否则嵌套 30 深度的包含大量数据的目录将无法告诉 C: 驱动器它有多大。

这是一个递归问题,您可以通过在每个子节点上调用函数来解决此问题,或者创建一个队列并在处理每个子节点时进行处理。

您也可以计算每个目录,然后让目录汇总它们的结果,或者您可以让每个文件报告。根据您的文件结构是宽还是深,这可能会有所不同,但可能可以忽略不计。

我把它写成一个队列,每个文件都向上报告。在我看来,如果你突破代码比使用调用堆栈和最终汇总更容易理解。

function Get-DirSize {
    [CmdletBinding()]
    param (
        [Parameter(Position = 0,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = "Directory path")]
        [ValidateNotNullOrEmpty()]
        $name = (Get-Item  ".")
        , [switch]$force
    )
    $name = Get-Item $name
    $q = New-Object System.Collections.Queue
    $results = New-Object System.Collections.Queue
    $q.Enqueue([PSCustomObject]@{
            Parent    = $null
            Directory = $name
            Size      = 0
            Depth     = 0
        })
    do {
        $dir = $q.Dequeue()
        $results.Enqueue($dir)
        $children = $dir.Directory | Get-ChildItem -Force:$force
        foreach ($child in $children) {
            if ($child.PSIsContainer ) {
                $q.Enqueue([PSCustomObject]@{
                        Parent    = $dir
                        Directory = $child
                        Size      = 0
                        Depth     = $dir.Depth + 1
                    })
            }
            else {
                $tempDir = $dir
                while ($tempDir) {
                    $tempDir.Size += $child.length
                    $tempDir = $tempDir.Parent
                }
            }
        }
    } until ($q.Count -eq 0)
    $ret = $results | ForEach-Object {
        $dir = $_
        return [PSCustomObject]@{
            FullName      = $dir.Directory.FullName
            LastWriteTime = $dir.Directory.LastWriteTime
            Size          = $dir.Size
            Depth         = $dir.Depth
            PSDirObject   = $dir.Directory
        } 
    }
    return $ret
}

然后你调用它,你可以传递一个你想要检查的目录,或者当前的工作目录。 -force 标志只是传递给 get-childitem 并且具有相同的效果。

Get-DirSize "c:\development" -force | Where-Object Depth -LE 3 | Select-Object FullName, LastWriteTime, @{n = "Size"; e = { "$($_.Size / 1MB)" + "MB" } }

输出必须按深度过滤,您可以使用自定义选择语句选择您想要的列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-29
    • 1970-01-01
    相关资源
    最近更新 更多