[英]A PowerShell script to find the file size and file count of a folder with millions of files?
該腳本的目的如下:
到目前為止(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"
然而,在包含數百萬個文件的文件夾中, $colitems
變量因收集數百萬個文件的信息而變得如此龐大,以至於使系統變得不穩定。 有沒有更有效的方法來繪制和存儲這些信息?
如果你使用流和流水線,你應該減少很多(3)的問題,因為當你使用 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 時,每個 object 在它們可用並且不占用太多 ZCD69B4957F06CD8298D7ZBF3D61 時沿着管道傳遞處理數百萬個文件(盡管這需要時間)。
Get-ChildItem $directory -recurse | Measure-Object -property length -sum
我不相信@Stej 的說法, Get-ChildItem probably reads all entries in the directory and then begins pushing them to the pipeline.
, 是真的。 流水線是 PowerShell 的一個基本概念(提供 cmdlet、腳本等支持它)。 它既確保處理的對象在可用時以及僅在需要時才沿管道傳遞。 Get-ChildItem
的行為不會有所不同。
了解 Windows PowerShell 管道中給出了一個很好的例子。
引用它:
每當您希望緩慢顯示冗長的 output 時,Out-Host -Paging 命令是一個有用的管道元素。 如果操作非常占用 CPU,則它特別有用。 由於處理會在准備好顯示完整頁面時轉移到 Out-Host cmdlet,因此管道中位於其前面的 cmdlet 會暫停操作,直到 output 的下一頁可用。 如果您使用 Windows 任務管理器來監控 CPU 和 memory 使用 Windows Z3D265B4E03BEEEF0DDF17881FA0,您可以看到這一點
運行以下命令:
Get-ChildItem C:\Windows -Recurse
。 將 CPU 和 memory 用法與以下命令進行比較:Get-ChildItem C:\Windows -Recurse | Out-Host -Paging
Get-ChildItem C:\Windows -Recurse | Out-Host -Paging
。
在 c:\ 上使用Get-ChildItem
的c:\
(大約 179516 個文件,不是數百萬,但足夠好):
運行$a = gci c:\ -recurse
(然后執行$a.count
)后的 Memory 使用量為527,332K
。
Memory 運行 gci 后的用法gci c:\ -recurse | measure-object
gci c:\ -recurse | measure-object
為59,452K
並且從未超過80,000K
左右。
(內存 - 私有工作集 - 來自 TaskManager,看到powershell.exe
進程的 memory。最初,它大約是22,000K
。)
我還嘗試了兩百萬個文件(我花了一些時間來創建它們!)
類似實驗:
運行$a = gci c:\ -recurse
(然后執行$a.count
)后的 Memory 使用量為2,808,508K
。
運行 gci 時 Memory 的使用gci c:\ -recurse | measure-object
gci c:\ -recurse | measure-object
為308,060K
並且從未超過400,000K
左右。 完成后,它必須執行[GC]::Collect()
才能返回到22,000K
級別。
我仍然相信Get-ChildItem
和流水線可以為您帶來出色的 memory 改進,即使對於數百萬個文件也是如此。
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
這里最昂貴的部分是帶有New-Object io.FileInfo $f
部分,因為EnumerateFiles
只返回文件名。 因此,如果只有文件數就足夠了,您可以注釋該行。
請參閱堆棧溢出問題如何使用 .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
}
比較:
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
...
@manojlds:流水線是一個基本概念。 但作為一個概念,它與提供者無關。 文件系統提供程序依賴於 .NET 實現 (.NET 2.0),它沒有延遲評估功能(~枚舉器)。 自己檢查一下。
下面的 function 很酷,計算文件夾大小的速度很快,但它並不總是有效(尤其是當有權限問題或文件夾路徑太長時)。
Function sizeFolder($path) # Return the size in MB.
{
$objFSO = New-Object -com Scripting.FileSystemObject
("{0:N2}" -f (($objFSO.GetFolder($path).Size) / 1MB))
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.