Esto usa GetCompressedFileSize, como se sugirió ho1, así como GetDiskFreeSpace, como sugería PaulStack ; sin embargo, usa P/Invoke. Lo he probado solo para archivos comprimidos, y sospecho que no funciona para archivos fragmentados.
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);
¿está seguro de que es correcto si (resultado == 0) lanza una nueva Win32Exception (resultado); – Simon
El bit 'if (result == 0)' es correcto (ver [msdn] (http://msdn.microsoft.com/en-us/library/aa364935.aspx)), pero tienes razón de que yo soy usando el constructor equivocado. Lo arreglaré ahora. – margnus1
'FileInfo.Directory.Root' no parece que pueda manejar ningún tipo de enlaces de sistema de archivos. Por lo tanto, solo funciona en letras de unidad locales clásicas sin enlaces simbólicos/enlaces permanentes/puntos de unión o lo que NTFS tiene para ofrecer. – ygoe