Używa GetCompressedFileSize, jak zasugerował ho1, a także GetDiskFreeSpace, jak sugeruje PaulStack , jednak używa P/Invoke. Przetestowałem to tylko w przypadku plików skompresowanych i podejrzewam, że nie działa w przypadku fragmentacji plików.
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);
czy jesteś pewien, że to jest poprawne if (result == 0) throw new Win32Exception (result); – Simon
Bit "if (result == 0)" jest poprawny (patrz [msdn] (http://msdn.microsoft.com/en-us/library/aa364935.aspx)), ale masz rację, że jestem używając niewłaściwego konstruktora. Naprawię to teraz. – margnus1
'FileInfo.Directory.Root' nie wygląda tak, jakby mógł obsłużyć dowolne linki systemu plików. Działa to wyłącznie na klasycznych dyskach lokalnych, bez dowiązań symbolicznych/twardych/punktów połączenia lub bez względu na to, co NTFS ma do zaoferowania. – ygoe