views:

178

answers:

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

This gives the logical size of the file, not the size on the disk. I wish to get the size on the disk in C# (preferably without interop) of a file as given by Windows Explorer.

Should give the correct size including for:

  • Compressed file
  • Sparse file
  • Fragmented file
+2  A: 

according to MSDN social forums

"The size on disk should be the sum of the size of the clusters that store the file: long sizeondisk = clustersize * ((filelength + clustersize - 1) / clustersize);

You'll need to dip into P/Invoke to find the cluster size; GetDiskFreeSpace() returns it."

http://social.msdn.microsoft.com/Forums/en-US/Vsexpressvcs/thread/85bf76ac-a254-41d4-a3d7-e7803c8d9bc3

but please note the point that this will not work in NTFS where compressed is switched on

PaulStack
I suggest using something like `GetCompressedFileSize` rather than `filelength` to account for compressed and/or sparse files.
ho1
A: 

If you consider that the size on disk will always be a multiple of 4k then you can get the size on disk this way:


float r = sizeInKB % 4;
float add = 4 - r;
sizeOnDiskInKB = sizeInKB + add;
sh_kamalh
It's not always 4k
Patrick
Cluster size is variable, file can be compressed, a sparse file, a symbolic link...
Wernight
+3  A: 

This uses GetCompressedFileSize, as ho1 suggested, as well as GetDiskFreeSpace, as PaulStack suggested, it does, however, use P/Invoke. I have tested it only for compressed files, and I suspect it does not work for fragmented files.

    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(result);
        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);
margnus1