2

设置 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
4

2 回答 2

2

如果您可以加快速度,我会感到惊讶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了参数,以防某些最大的文件被隐藏。

于 2016-11-07T06:06:10.787 回答
1

稍作调整——实例化 aSystem.Collections.ArrayList来存储文件长度列表——在同一目录上执行查询的时间几乎减半。当您向其中添加新项目时,您不会不断地创建/销毁标准的固定大小的数组。

此示例的 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

整洁的多行版本:

$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
于 2016-11-07T04:18:08.533 回答