简体   繁体   English

使用Powershell在磁盘上查找目录空间

[英]Find directory space on disk with powershell

I wanted to know the size of my different sub-directories, so I followed the indications of Getting Directory sizes powershell and Display directory structure in powershell and some others here in SO and somewhere else. 我想知道不同子目录的大小,所以我遵循在Powershell中获取目录大小powershellDisplay目录结构的指示,在SO中以及其他地方使用其他指示。 Those functions work well, except I want to know the space that some partially synced folders occupy in disk (for example, I have a folder in Skydrive with only some of its sub-folders available online). 这些功能运行良好,只不过我想知道某些部分同步的文件夹在磁盘上所占的空间(例如,我在Skydrive中有一个文件夹,其中只有一些子文件夹可在线使用)。 When I call either function, they report the size of the folder as if it were in disk , not the actual disk usage. 当我调用这两个函数时,它们会报告该文件夹的大小, 就像它在磁盘中一样 ,而不是实际的磁盘使用情况。 If I right-click the folder and check its properties, I can see clearly there is a difference between size and size in disk . 如果右键单击该文件夹并检查其属性,则可以清楚地看到size in disk sizesize in disk之间存在差异。

I have tried with Sort-Object -Property Size and Sort-Object -Property Length switches to either function (mostly based in the Get-ChildItem function), but both of them return size and not size in disk. 我尝试使用Sort-Object -Property SizeSort-Object -Property Length切换到任一函数(主要基于Get-ChildItem函数),但是它们两者都返回大小,而不是磁盘大小。

I guess there is a simple switch to make it take into account only actual disk usage, instead of total size, but I'm completely lost as to how to achieve it. 我想有一个简单的开关可以使它仅考虑实际磁盘使用情况,而不是总大小,但是我完全不知道如何实现它。 Any leads are much appreciated! 任何线索都非常感谢!

Thanks, 谢谢,

Size On Disk is the actual size that your files occupy on the drive depending on the cluster size (or allocation unit), which most of the time is 4KB, but not all of the time. “磁盘大小”是文件在驱动器上实际占用的大小,具体取决于群集大小(或分配单位),大多数情况下为4KB,但并非始终如此。 It depends on the file format and how it was formatted. 这取决于文件格式及其格式。

As long as the files are not compressed, it's a matter of finding out how many chunks of clusters are needed to fit each file. 只要不压缩文件,就可以找出需要多少簇的簇来容纳每个文件。 Keeping in mind that if a file is smaller than the cluster size, it will occupy one allocation unit. 请记住,如果文件小于群集大小,则它将占用一个分配单位。

If the file is compressed, the information is not easily available and needs to be retrieved via an API. 如果文件被压缩,则信息不容易获得,需要通过API进行检索。

The following code is divided in 3 main sections: 以下代码分为3个主要部分:

  1. It defines a Type used to access the function GetCompressedFileSizeAPI in kernel.dll. 它定义了一个Type,用于访问GetCompressedFileSizeAPI中的函数GetCompressedFileSizeAPI This function will retrieve the compressed size on disk of the file. 此函数将检索文件磁盘上的压缩大小。
  2. It uses WMI to determine the cluster size for the given $path 它使用WMI确定给定$path的群集大小
  3. It computes the Size on Disk for the files in the folder and subfolders of $path depending if the file is compressed or not. 它为文件夹中$path子文件夹和子文件夹中的文件计算磁盘大小,具体取决于文件是否经过压缩。

Note that the call to Get-ChildItem uses the -force switch to ensure we retrieve hidden and system files as well. 请注意,对Get-ChildItem的调用使用-force开关来确保我们也检索隐藏文件和系统文件。

I'm not sure if this code will work with Skydrive, so you might need to change the WMI part. 我不确定该代码是否可与Skydrive一起使用,因此您可能需要更改WMI部分。

$path = '.\'

Add-Type -TypeDefinition @" 
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;

public class FileInfo 
{ 
    [DllImport("kernel32.dll", SetLastError=true, EntryPoint="GetCompressedFileSize")]
    static extern uint GetCompressedFileSizeAPI(string lpFileName, out uint lpFileSizeHigh);

    public static ulong GetCompressedFileSize(string strFileName)
    {
        uint intHigh;
        uint intLow;
        intLow = GetCompressedFileSizeAPI(strFileName, out intHigh);
        int intError = Marshal.GetLastWin32Error();
        if (intHigh == 0 && intLow == 0xFFFFFFFF && intError != 0)
            throw new Win32Exception(intError);
        else
            return ((ulong)intHigh << 32) + intLow;
    }
} 
"@


$files = Get-ChildItem $path -Recurse -force | where {$_.PSIsContainer -eq $false}

$drive = [string]$files[0].PSdrive+':'
$wql = "SELECT Blocksize FROM Win32_Volume where DriveLetter='$drive'"
$driveinfo = Get-WmiObject -Query $wql -ComputerName '.' 

$sizeondisk = ($files | %{      
    if ($_.Attributes -like "*compressed*")
    {

        if ($_.length -lt $driveinfo.BlockSize -and $_.length -ne 0)
        {
            $driveinfo.BlockSize
        }
        else
        {
            [FileInfo]::GetCompressedFileSize($_.fullname)
        }
    }
    else
    {
        if ($_.length -lt $driveinfo.BlockSize -and $_.length -ne 0)
        {
            $driveinfo.BlockSize
        }
        else
        {
            ([math]::ceiling($_.length/$driveinfo.BlockSize))*$driveinfo.BlockSize
        }
    }
}|Measure -sum).sum

$sizeondisk

UPDATE for Sparse Files: 稀疏文件的更新:

Let's see if this version works with sparse files, add this block of code at the end of the previous code, keep everything else the same: 让我们看看该版本是否适用于稀疏文件,在之前的代码末尾添加此代码块,并保持其他所有内容不变:

$sparsesize = ($files | %{      
    if ($_.length -lt $driveinfo.BlockSize -and $_.length -ne 0)
    {
        $driveinfo.BlockSize
    }
    else
    {
        $_.fullname
        [FileInfo]::GetCompressedFileSize($_.fullname)
    }
}|Measure -sum).sum

$sparsesize

Sources: 资料来源:

Understanding NTFS compression 了解NTFS压缩

Help querying files to return SIZE on DISK 帮助查询文件以在DISK上返回SIZE

Size of compressed files (in French) 压缩文件的大小(法语)

How to get the actual size-on-disk of a file from PowerShell? 如何从PowerShell获取文件的实际磁盘大小?

Default cluster size for NTFS, FAT, and exFAT NTFS,FAT和exFAT的默认群集大小

For some reason, I was encountering errors in regards to certain values being strings and not numeric in the sparse file code snippet. 由于某些原因,我在稀疏文件代码片段中遇到某些值是字符串而不是数字的错误。

However, I noticed when I took out the " $_.fullname" from below 但是,当我从下面取出“ $ _。fullname”时,我注意到了

$sparsesize = ($files | %{      
if ($_.length -lt $driveinfo.BlockSize -and $_.length -ne 0)
{
    $driveinfo.BlockSize
}
else
{
    $_.fullname
    [FileInfo]::GetCompressedFileSize($_.fullname)
}
}|Measure -sum).sum

$sparsesize

and change it to 并将其更改为

$sparsesize = ($files | %{      
if ($_.length -lt $driveinfo.BlockSize -and $_.length -ne 0)
{
    $driveinfo.BlockSize
}
else
{
    [FileInfo]::GetCompressedFileSize($_.fullname)
}
}|Measure -sum).sum

$sparsesize

Then it returned a numeric value. 然后,它返回一个数值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM