计算DFS文件夹分段大小的前32个文件大小的更好方法

时间:2016-11-07 04:18:09

标签: powershell dfs

设置DFS副本时的一个常见任务是确定已复制文件夹中32个最大文件的大小 - 根据当前的最佳实践,这些文件的总和应该是暂存区域的最小大小。

在Technet博客中提供了查找和计算此前32个文件大小的方法:https://blogs.technet.microsoft.com/askds/2011/07/13/how-to-determine-the-minimum-staging-area-dfsr-needs-for-a-replicated-folder/

它依赖于使用Get-ChildItem在路径中查找所有文件及其大小,按大小排序,丢弃除32位之外的所有文件,然后计算总和。

当您的路径中包含有限数量的文件时,这很好,但在索引具有数十万(甚至数百万个文件)的文件夹时存在严重缺陷。该进程在执行时将所有内容转储到内存中 - 在我的示例中,它消耗超过2GB的虚拟内存 - 并且需要很长时间,即使单个文件非常小。在PS实例关闭之前,内存将保持分配状态。

PS C:\> measure-command { (get-childitem F:\Folder\with\966693\items -recurse | 
sort-object length -descending | select-object -first 32 | 
measure-object -property length -sum).sum }
Days              : 0
Hours             : 0
Minutes           : 6
Seconds           : 6
Milliseconds      : 641
Ticks             : 3666410633
TotalDays         : 0.00424353082523148
TotalHours        : 0.101844739805556
TotalMinutes      : 6.11068438833333
TotalSeconds      : 366.6410633
TotalMilliseconds : 366641.0633

2 个答案:

答案 0 :(得分:1)

如果您可以加快Get-ChildItem的速度,我会感到惊讶,除非您可以避免为每个文件构建[IO.FileInfo]个对象(.Net DirectorySearcher可能?)。

但是你可以通过不保留所有结果来减少内存需求,在这个例子中只保留正在进行的N最大值100,但是可以调整到测试内存/性能,例如。

$BufferSize = 100
$FileSizes = New-Object System.Collections.ArrayList

Get-ChildItem 'd:\downloads' -Force -Recurse -File | ForEach {

    $null = $FileSizes.Add($_.Length)
    if ($FileSizes.Count -gt $BufferSize)
    {
        $FileSizes.Sort()
        $FileSizes.RemoveRange(0, ($BufferSize-32))
    }
}
($FileSizes[0..31] | measure-object -Sum).Sum/1GB

在某些最大的文件被隐藏的情况下,向gci添加了-Force参数。

答案 1 :(得分:0)

稍微调整 - 实例化System.Collections.ArrayList以存储文件长度列表 - 在同一目录上执行查询的时间几乎减半。在您向其中添加新项目时,您需要not constantly creating/destroying a standard fixed-sized array

此样本的Powershell进程的内存使用量仍低于900MB。如果我想重用PS控制台,我也喜欢将变量设置为$ null。

measure command { $total = New-Object System.Collections.ArrayList; 
gci F:\Folder\with\966693\items -file -r | 
ForEach { $total.Add($_.length)>$null } ; 
(($total | sort -descending | select -first 32 |measure-object -sum).sum/1GB) }
Days              : 0
Hours             : 0
Minutes           : 3
Seconds           : 34
Milliseconds      : 215
Ticks             : 2142159038
TotalDays         : 0.00247935073842593
TotalHours        : 0.0595044177222222
TotalMinutes      : 3.57026506333333
TotalSeconds      : 214.2159038
TotalMilliseconds : 214215.9038

Tidier多线版:

$total = New-Object System.Collections.ArrayList
gci F:\Folder\with\966693\items  -file -r | ForEach { $total.Add($_.length)>$null } 
($total | sort -descending | select -first 32 | measure-object -sum).sum/1GB