Sergey Shishkin

on agile software development

How to get the ‘size on disk’?

“A cluster is the smallest logical amount of disk space that can be allocated to hold a file” — Wikipedia. It means that if you have a 100 bytes text file it will waste at least one cluster (usually 4096 bytes), but always a whole number of clusters. On the other hand, if you have applied the file system compression to the 100KB text file it might likely use only a half of its actual size. So, if you see the file’s properties in the Windows Explorer there are two sizes: Size and Size on disk.

Managed .NET API provides only the size of the file’s content (FileInfo.Length property). Although the size the file occupy on the disk is more useful in some cases. But how one can get it?

There are two Win32 functions: GetCompressedFileSize and GetDiskFreeSpace. The former will return the right size only if the file is compressed. Elsewise you need to use the latter to get the cluster size (it returns the number of sectors per cluster and the number of bytes per sector) and manually calculate the result. Here is the code:

public static long GetSizeOnDisk (string fileName)

{

  FileInfo file = newFileInfo(fileName);

  if ((file.Attributes & FileAttributes.Compressed) > 0)

  {

    return GetCompressedFileSize(file.FullName);

  }

  else

  {

    long clusterSize = GetDiskClusterSize(

      file.Directory.Root.FullName);

 

    long sizeOnDisk = file.Length;

    long overload = sizeOnDisk % clusterSize;

    if (overload != 0)

    {

      sizeOnDisk += (clusterSize – overload);

    }

    return sizeOnDisk;

  }

}

 

private static long GetCompressedFileSize (string fileName)

{

  uint high;

  uint low;

 

  low = GetCompressedFileSize(fileName, out high);

 

  int error = Marshal.GetLastWin32Error();

  if (high == 0 && low == 0xFFFFFFFF && error != 0)

  {

    thrownewWin32Exception(error);

  }

 

  return (long)(((ulong)high << 32) + low);

}

 

private static int GetDiskClusterSize (string driveName)

{

  uint sectorsPerCluster;

  uint bytesPerSector;

  uint numberOfFreeClusters;

  uint totalNumberOfClusters;

 

  if (GetDiskFreeSpace(driveName,

    out sectorsPerCluster,

    out bytesPerSector,

    out numberOfFreeClusters,

    out totalNumberOfClusters))

  {

    return (int)sectorsPerCluster * (int)bytesPerSector;

  }

  else

  {

    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

    return -1;

  }

}

 

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

private static extern uint GetCompressedFileSize (

  string lpFileName, outuint lpFileSizeHigh);

 

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

private static extern bool GetDiskFreeSpace (

  string lpRootPathName,

  outuint lpSectorsPerCluster,

  outuint lpBytesPerSector,

  outuint lpNumberOfFreeClusters,

  outuint lpTotalNumberOfClusters);

Advertisements

Written by Sergey Shishkin

25.01.2007 at 18:14

Posted in Uncategorized

%d bloggers like this: