Diskteki dosyanın boyutunu alın


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

Bu, diskteki boyutu değil dosyanın mantıksal boyutunu verir.

Windows Gezgini tarafından bildirildiği gibi diskteki bir dosyanın boyutunu C # olarak (tercihen birlikte çalışmadan ) almak istiyorum.

Aşağıdakiler dahil doğru boyutu vermelidir:

  • Sıkıştırılmış bir dosya
  • Seyrek bir dosya
  • Parçalanmış bir dosya

Yanıtlar:


50

Bu, ho1'in önerdiği gibi GetCompressedFileSize ve PaulStack'in önerdiği gibi GetDiskFreeSpace'i kullanır, ancak P / Invoke kullanır. Yalnızca sıkıştırılmış dosyalar için test ettim ve parçalanmış dosyalar için çalışmadığından şüpheleniyorum.

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);

(sonuç == 0) yeni Win32Exception (sonuç) atarsanız bunun doğru olduğundan emin misiniz;
Simon

'If (sonuç == 0)' biti doğrudur ( msdn'ye bakın ), ancak yanlış yapıcıyı kullanıyorum konusunda haklısınız. Şimdi düzelteceğim.
margnus1

FileInfo.Directory.Rootherhangi bir dosya sistemi bağlantısını işleyebilecek gibi görünmüyor. Bu nedenle, yalnızca sembolik bağlar / sabit bağlantılar / birleşme noktaları veya NTFS'nin sunduğu herhangi bir şey olmadan klasik yerel sürücü harfleri üzerinde çalışır.
ygoe

Lütfen adım adım açıklama yapabilir mi, farklı adımlarda neler yapıldı? Gerçekte nasıl çalıştığını anlamak çok yardımcı olacaktır.
bapi

5
Bu kod, ad alanlarını System.ComponentModelve System.Runtime.InteropServices.
Kenny Evitt

17

Küme boyutu her zaman sıfır olduğundan yukarıdaki kod Windows Server 2008 veya 2008 R2 veya Windows 7 ve Windows Vista tabanlı sistemlerde düzgün çalışmaz (GetDiskFreeSpaceW ve GetDiskFreeSpace, UAC devre dışıyken bile -1 döndürür .) İşte çalışan değiştirilmiş kod.

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

Bu kodun çalışması için System.Managment referansı gereklidir. WMI dışında Windows'ta (6.x sürümleri) küme boyutunu doğru bir şekilde almanın standart bir yolu yokmuş gibi görünüyor. : |
Steve Johnson

1
Kodumu bir Vista x64 makinesinde yazdım ve şimdi 64 bit ve WOW64 modunda bir W7 x64 makinede test ettim. GetDiskFreeSpace'in başarı durumunda sıfırdan farklı bir değer döndürmesi gerektiğini unutmayın .
margnus1

1
Orijinal soru C # için soruyor
Shane Courtrille

4
Bu kod bile (bir sağ ayraç kullanarak eksik) derleme değil ve bir astar öğrenme amaçlı çok korkunç
Mickael V.

1
Bu kod, bir kod ilk çağrısını kullanmak istiyorsanız .First(), an IEnumerabledeğil , bir istekte bulunurken bir derleme sorununa da sahiptirIEnumerable<T>.Cast<object>()
yoel halb

5

MSDN sosyal forumlarına göre:

Diskteki boyut, dosyayı depolayan kümelerin boyutlarının toplamı olmalıdır: Küme boyutunu bulmak için P / Invoke'a
long sizeondisk = clustersize * ((filelength + clustersize - 1) / clustersize);
girmeniz gerekir ;GetDiskFreeSpace()onu döndürür.

C # 'da bir dosyanın diskindeki boyutu nasıl elde edilir konusuna bakın .

Ancak , sıkıştırmanın etkinleştirildiği NTFS'de bunun çalışmayacağına lütfen dikkat edin .


2
Sıkıştırılmış ve / veya seyrek dosyaları hesaba katmak GetCompressedFileSizeyerine benzeri bir şey kullanmanızı öneririm filelength.
Hans Olsson

-1

Sanırım şöyle olacak:

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

Onay almak için hala bunun için bazı testler yapıyorum.


7
Bu, dosyanın boyutudur (dosya içindeki bayt sayısı). Gerçek donanımın blok boyutlarına bağlı olarak, bir dosya daha fazla disk alanı tüketebilir. Örneğin, sabit diskteki 600 baytlık bir dosya diskte 4kB kullandı. Yani bu cevap yanlış.
0xBADF00D
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.