ディスク上のファイルのサイズを取得します


85
var length = new System.IO.FileInfo(path).Length;

これにより、ディスク上のサイズではなく、ファイルの論理サイズがわかります。

Windowsエクスプローラーで報告されるように、C#で(できれば相互運用機能なしで)ディスク上のファイルのサイズを取得したいと思います。

次のような正しいサイズを指定する必要があります。

  • 圧縮ファイル
  • スパースファイル
  • 断片化されたファイル

回答:


50

これは、ho1が提案したようにGetCompressedFileSizeを使用し、PaulStackが提案したようにGetDiskFreeSpaceを使用しますが、P / Invokeを使用します。圧縮ファイルについてのみテストしましたが、断片化されたファイルでは機能しないと思われます。

public static long GetFileSizeOnDisk(string file)
{
    FileInfo info = new FileInfo(file);
    uint dummy, sectorsPerCluster, bytesPerSector;
    int result = GetDiskFreeSpaceW(info.Directory.Root.FullName, out sectorsPerCluster, out bytesPerSector, out dummy, out dummy);
    if (result == 0) throw new Win32Exception();
    uint clusterSize = sectorsPerCluster * bytesPerSector;
    uint hosize;
    uint losize = GetCompressedFileSizeW(file, out hosize);
    long size;
    size = (long)hosize << 32 | losize;
    return ((size + clusterSize - 1) / clusterSize) * clusterSize;
}

[DllImport("kernel32.dll")]
static extern uint GetCompressedFileSizeW([In, MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
   [Out, MarshalAs(UnmanagedType.U4)] out uint lpFileSizeHigh);

[DllImport("kernel32.dll", SetLastError = true, PreserveSig = true)]
static extern int GetDiskFreeSpaceW([In, MarshalAs(UnmanagedType.LPWStr)] string lpRootPathName,
   out uint lpSectorsPerCluster, out uint lpBytesPerSector, out uint lpNumberOfFreeClusters,
   out uint lpTotalNumberOfClusters);

(result == 0)throw new Win32Exception(result);の場合、これが正しいと確信していますか。
サイモン

'if(result == 0)'ビットは正しいですが(msdnを参照)、間違ったコンストラクターを使用しているのは正しいです。今すぐ修正します。
margnus1 2011

FileInfo.Directory.Rootあらゆる種類のファイルシステムリンクを処理できるようには見えません。したがって、シンボリックリンク/ハードリンク/ジャンクションポイントやNTFSが提供するものがない従来のローカルドライブ文字でのみ機能します。
ygoe 2013

誰かがステップバイステップの説明をしてくれませんか、異なるステップで何が行われたのですか?それが実際にどのように機能するかを理解することは非常に役立ちます。ありがとう。
bapi 2013年

5
このコードには名前空間System.ComponentModelとが必要System.Runtime.InteropServicesです。
ケニーエビット2014

17

上記のコードは、上で正常に動作しないWindows Server 2008のクラスタサイズが常にゼロであるとして、または2008 R2またはWindows 7およびWindows Vistaベースのシステム(GetDiskFreeSpaceWとGetDiskFreeSpaceのリターン-1でもとUAC無効。)ここで変更されたコードは、作品ということです。

C#

public static long GetFileSizeOnDisk(string file)
{
    FileInfo info = new FileInfo(file);
    uint clusterSize;
    using(var searcher = new ManagementObjectSearcher("select BlockSize,NumberOfBlocks from Win32_Volume WHERE DriveLetter = '" + info.Directory.Root.FullName.TrimEnd('\\') + "'") {
        clusterSize = (uint)(((ManagementObject)(searcher.Get().First()))["BlockSize"]);
    }
    uint hosize;
    uint losize = GetCompressedFileSizeW(file, out hosize);
    long size;
    size = (long)hosize << 32 | losize;
    return ((size + clusterSize - 1) / clusterSize) * clusterSize;
}

[DllImport("kernel32.dll")]
static extern uint GetCompressedFileSizeW(
   [In, MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
   [Out, MarshalAs(UnmanagedType.U4)] out uint lpFileSizeHigh);

VB.NET

  Private Function GetFileSizeOnDisk(file As String) As Decimal
        Dim info As New FileInfo(file)
        Dim blockSize As UInt64 = 0
        Dim clusterSize As UInteger
        Dim searcher As New ManagementObjectSearcher( _
          "select BlockSize,NumberOfBlocks from Win32_Volume WHERE DriveLetter = '" + _
          info.Directory.Root.FullName.TrimEnd("\") + _
          "'")

        For Each vi As ManagementObject In searcher.[Get]()
            blockSize = vi("BlockSize")
            Exit For
        Next
        searcher.Dispose()
        clusterSize = blockSize
        Dim hosize As UInteger
        Dim losize As UInteger = GetCompressedFileSizeW(file, hosize)
        Dim size As Long
        size = CLng(hosize) << 32 Or losize
        Dim bytes As Decimal = ((size + clusterSize - 1) / clusterSize) * clusterSize

        Return CDec(bytes) / 1024
    End Function

    <DllImport("kernel32.dll")> _
    Private Shared Function GetCompressedFileSizeW( _
        <[In](), MarshalAs(UnmanagedType.LPWStr)> lpFileName As String, _
        <Out(), MarshalAs(UnmanagedType.U4)> lpFileSizeHigh As UInteger) _
        As UInteger
    End Function

このコードを機能させるには、System.Managment参照が必要です。WMIを除いて、Windows(6.xバージョン)でクラスターサイズを正確に取得する標準的な方法がないように見えます。:|
スティーブジョンソン

1
私はVistax64マシンでコードを記述し、64ビットおよびWOW64モードのW7x64マシンでテストしました。GetDiskFreeSpaceは、成功するとゼロ以外を返すことになっていることに注意してください。
margnus1 2011

1
元の質問はC#を要求します
Shane Courtrille 2013年

4
このコードはコンパイルすらされておらず(使用時に1つの閉じ括弧が欠落しています)、1つのライナーは学習目的にとって非常にひどいです
Mickael V.

1
要求するときに、このコードはコンパイル問題があり.First()、それがあるとしてIEnumerableではなくIEnumerable<T>、コードの最初の呼び出しを使用したい場合は、.Cast<object>()
ヨエルHALB

5

MSDNソーシャルフォーラムによると:

ディスク上のサイズは、ファイルを格納するクラスターのサイズの合計である
long sizeondisk = clustersize * ((filelength + clustersize - 1) / clustersize);
必要があります。クラスターサイズを見つけるには、P / Invokeにアクセスする必要があります。GetDiskFreeSpace()それを返します。

C#でファイルのディスク上のサイズを取得する方法を参照してください。

ただし、これは圧縮がオンになっているNTFSでは機能しないことに注意してください。


2
圧縮ファイルやスパースファイルを説明するのGetCompressedFileSizeではなく、のようなものを使用することをお勧めしfilelengthます。
ハンスオルソン2010

-1

私はそれがこのようになると思います:

double ifileLength = (finfo.Length / 1048576); //return file size in MB ....

確認を得るために、私はまだこれについていくつかのテストを行っています。


7
これはファイルのサイズ(ファイル内のバイト数)です。実際のハードウェアのブロックサイズによっては、ファイルがより多くのディスク領域を消費する場合があります。たとえば、HDD上の600バイトのファイルはディスク上で4kBを使用していました。したがって、この答えは正しくありません。
0xBADF00D 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.