Добрый день.
Пишу на C# программу, которая должна высчитывать рекурсивно размер папок и файлов на диске.
Считал, что размер файла на диске равен длине файла, округленной вверх до целого числа кластеров. Также нужно нужно учитывать сжатые/разреженные файлы. Для получения данных о файловой системе использую функцию GetDiskFreeSpaceW, для получения размера файла - функцию GetCompressedFileSizeW.
Но сейчас заметил, что есть маленькие файлы, примерно до 500 байт, которые в меню "Свойства" занимают 0 байт на диске.
Экспериментировал, создавал файл с пустого, до 500 байт он не занимает места на диске, а потом начинает занимать целый кластер, даже если начать уменьшать этот файл до размера меньше 500 байт.
Здесь нашел какое-то объяснение
Вопрос - можно как-нибудь получить программно "правильный" размер таких файлов на диске, как это делает меню "Свойства"?
Функция, которую использую для получения размера файла
public static long GetFileSizeOnDisk(string file_path)
{
string root_dir = "";
for (int i = 0; i < file_path.Length; i++)
{
root_dir += file_path[i];
if (file_path[i] == '\\' || (i == file_path.Length - 1))
break;
}
if (!file_path.StartsWith(@"\\?\"))
file_path = @"\\?\" + file_path; // чтобы не было ошибки при длинных путях
//FileInfo info = new FileInfo(file_path);
uint dummy, sectorsPerCluster, bytesPerSector;
int result = GetDiskFreeSpaceW(root_dir, out sectorsPerCluster, out bytesPerSector, out dummy, out dummy);
//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_path, 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);