该脚本的目的如下:
到目前为止(3)是艰难的部分.
这是我到目前为止编写和测试的内容.这适用于具有一百甚至一千个文件的文件夹:
$hostname=hostname
$directory = "foo"
$dteCurrentDate = Get-Date –f "yyyy/MM/dd"
$FolderItems = Get-ChildItem $directory -recurse
$Measurement = $FolderItems | Measure-Object -property length -sum
$colitems = $FolderItems | measure-Object -property length -sum
"$hostname;{0:N2}" -f ($colitems.sum / 1MB) + "MB;" + $Measurement.count + " files;" + "$dteCurrentDate"
Run Code Online (Sandbox Code Playgroud)
但是,在包含数百万个文件的文件夹中,$colitems
变量从数百万个文件的信息集合中变得如此庞大,这使得系统不稳定.有没有更有效的方法来绘制和存储这些信息?
man*_*lds 36
如果你使用流和流水线,你应该减少(3)很多问题,因为当你流,每个对象在它们可用时传递沿着管道,并且不占用太多内存,你应该能够处理数百万个文件(虽然需要时间).
Get-ChildItem $directory -recurse | Measure-Object -property length -sum
Run Code Online (Sandbox Code Playgroud)
我不相信@ Stej的陈述Get-ChildItem probably reads all entries in the directory and then begins pushing them to the pipeline.
,是真的.流水线操作是PowerShell的基本概念(提供cmdlet,脚本等支持它).它既可以确保处理过的对象在它们可用时一个接一个地传递给管道,并且只有在需要它们时才会这样.Get-ChildItem
不会表现得不同.
在了解Windows PowerShell管道中给出了一个很好的例子.
引用它:
只要您想要缓慢显示冗长的输出,Out-Host -Paging命令就是一个有用的管道元素.如果操作非常耗费CPU,那么它尤其有用.由于处理在准备好显示完整页面时会传输到Out-Host cmdlet,因此管道中的cmdlet会在管道暂停操作之前停止,直到输出的下一页可用.如果使用Windows任务管理器监视Windows PowerShell的CPU和内存使用情况,则可以看到此信息.
运行以下命令:
Get-ChildItem C:\Windows -Recurse
.将CPU和内存使用情况与此命令进行比较:Get-ChildItem C:\Windows -Recurse | Out-Host -Paging
.
基准上使用Get-ChildItem
的c:\
(约179516文件,而不是milions,但不够好):
运行$a = gci c:\ -recurse
(然后执行$a.count
)后的内存使用情况是527,332K
.
运行后的内存使用量gci c:\ -recurse | measure-object
是59,452K
与上述各地从来没有去80,000K
.
(内存 - 私有工作集 - 来自TaskManager,查看powershell.exe
进程的内存.最初,它是关于22,000K
.)
我还尝试了两百万个文件(创建它们需要一段时间!)
类似实验:
运行$a = gci c:\ -recurse
(然后执行$a.count
)后的内存使用情况是2,808,508K
.
运行gci c:\ -recurse | measure-object
时的内存使用率308,060K
从未超过400,000K
.完成后,它必须做一个[GC]::Collect()
让它返回到22,000K
关卡.
我仍然相信,Get-ChildItem
即使对于数百万个文件,流水线操作也可以为您带来出色的内存改进.
ste*_*tej 10
Get-ChildItem
可能会读取目录中的所有条目,然后开始将它们推送到管道.如果Get-ChildItem
不能正常工作,请尝试切换到.NET 4.0并使用EnumerateFiles
和EnumeratedDirectories
:
function Get-HugeDirStats($directory) {
function go($dir, $stats)
{
foreach ($f in [system.io.Directory]::EnumerateFiles($dir))
{
$stats.Count++
$stats.Size += (New-Object io.FileInfo $f).Length
}
foreach ($d in [system.io.directory]::EnumerateDirectories($dir))
{
go $d $stats
}
}
$statistics = New-Object PsObject -Property @{Count = 0; Size = [long]0 }
go $directory $statistics
$statistics
}
#example
$stats = Get-HugeDirStats c:\windows
Run Code Online (Sandbox Code Playgroud)
这里最昂贵的部分是一个New-Object io.FileInfo $f
,因为EnumerateFiles
只返回文件名.因此,如果只有文件数量就足够了,您可以对该行进行注释.
请参阅Stack Overflow问题如何使用.NET 4运行时运行PowerShell? 学习如何使用.NET 4.0.
您也可以使用也很快的普通旧方法,但是读取目录中的所有文件.所以这取决于你的需求,试试吧.后来有所有方法的比较.
function Get-HugeDirStats2($directory) {
function go($dir, $stats)
{
foreach ($f in $dir.GetFiles())
{
$stats.Count++
$stats.Size += $f.Length
}
foreach ($d in $dir.GetDirectories())
{
go $d $stats
}
}
$statistics = New-Object PsObject -Property @{Count = 0; Size = [long]0 }
go (new-object IO.DirectoryInfo $directory) $statistics
$statistics
}
Run Code Online (Sandbox Code Playgroud)
比较:
Measure-Command { $stats = Get-HugeDirStats c:\windows }
Measure-Command { $stats = Get-HugeDirStats2 c:\windows }
Measure-Command { Get-ChildItem c:\windows -recurse | Measure-Object -property length -sum }
TotalSeconds : 64,2217378
...
TotalSeconds : 12,5851008
...
TotalSeconds : 20,4329362
...
Run Code Online (Sandbox Code Playgroud)
@manojlds:流水线是一个基本概念.但作为一个概念,它与提供者无关.文件系统提供程序依赖于没有惰性评估功能(〜枚举器)的.NET实现(.NET 2.0).检查一下你自己.
归档时间: |
|
查看次数: |
74256 次 |
最近记录: |