Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get size of file on disk

Tags:

c#

.net

filesize

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 of a file on the disk in C# (preferably without interop) as would be reported by Windows Explorer.

It should give the correct size, including for:

  • A compressed file
  • A sparse file
  • A fragmented file
like image 513
Wernight Avatar asked Sep 20 '10 10:09

Wernight


People also ask

How do I check the size of a file in Linux?

Using the ls Command –l – displays a list of files and directories in long format and shows the sizes in bytes. –h – scales file sizes and directory sizes into KB, MB, GB, or TB when the file or directory size is larger than 1024 bytes. –s – displays a list of the files and directories and shows the sizes in blocks.

How do I find the size of a file in Windows?

Go to Windows Explorer and right-click on the file, folder or drive that you're investigating. From the menu that appears, go to Properties. This will show you the total file/drive size.

How do I view file sizes in Windows 10?

How can I see a file's size in Windows 10? Go to File Explorer and right-click the Name field. Select Size. File sizes will now display on the right side of the window.


2 Answers

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();     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); 
like image 93
margnus1 Avatar answered Oct 11 '22 05:10

margnus1


The code above does not work properly on Windows Server 2008 or 2008 R2 or Windows 7 and Windows Vista based systems as cluster size is always zero (GetDiskFreeSpaceW and GetDiskFreeSpace return -1 even with UAC disabled.) Here is the modified code that works.

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 
like image 36
Steve Johnson Avatar answered Oct 11 '22 05:10

Steve Johnson