Получить размер файла на диске

var length = new System.IO.FileInfo(path).Length;

Это дает логический размер файла, а не размер на диске.

Я хочу получить размер файла на диске в C # (желательно без interop ), как сообщалось бы в Windows Explorer.

Он должен давать правильный размер, в том числе для:

  • Сжатый файл
  • разреженный файл
  • Фрагментированный файл
79 голосов | спросил Wernight 20 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 20 Sep 2010 14:37:02 +0400 2010, 14:37:02

4 ответа


0

При этом используется GetCompressedFileSize, как предлагалось ho1, а также GetDiskFreeSpace, как PaulStack  предложил, однако, использовать P /Invoke. Я проверил его только для сжатых файлов, и я подозреваю, что он не работает для фрагментированных файлов.

    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);
ответил margnus1 20 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 20 Sep 2010 15:45:36 +0400 2010, 15:45:36
0

Приведенный выше код не работает должным образом в Windows Server 2008 или 2008 R2 или Windows 7 и Системы на основе Windows Vista, поскольку размер кластера всегда равен нулю (GetDiskFreeSpaceW и GetDiskFreeSpace возвращают -1, даже если UAC отключен .) Вот модифицированный код, который работает.

С #

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
ответил Steve Johnson 29 J000000Friday11 2011, 08:58:43
0

Согласно социальным форумам MSDN:

  

Размер на диске должен быть суммой размера кластеров, в которых хранится файл:
long sizeondisk = clustersize * ((filelength + clustersize - 1) / clustersize);   
  Вам нужно будет окунуться в P /Invoke , чтобы узнать размер кластера; GetDiskFreeSpace() возвращает его.

См. Как получить размер на диске файла в C # .

Но учтите, что это не будет работать в NTFS , где включено сжатие .

ответил stack72 20 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 20 Sep 2010 14:47:20 +0400 2010, 14:47:20
0

Я думаю, что это будет так:

double ifileLength = (finfo.Length / 1048576); //return file size in MB ....

Я все еще проверяю это, чтобы получить подтверждение.

ответил bapi 13 32013vEurope/Moscow11bEurope/MoscowWed, 13 Nov 2013 17:39:58 +0400 2013, 17:39:58

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132