디스크의 파일 크기 가져 오기


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

이것은 디스크의 크기가 아닌 파일의 논리적 크기를 제공합니다.

Windows 탐색기에서보고 한대로 C # (바람직하게는 interop 없이 ) 의 디스크에있는 파일의 크기를 얻고 싶습니다 .

다음을 포함하여 올바른 크기를 제공해야합니다.

  • 압축 파일
  • 스파 스 파일
  • 조각난 파일

답변:


50

이것은 ho1이 제안한대로 GetCompressedFileSize를 사용하고 PaulStack이 제안한대로 GetDiskFreeSpace를 사용하지만 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);

(result == 0) throw new Win32Exception (result); 이것이 맞다고 확신합니까?
Simon

'if (result == 0)'비트는 정확 하지만 ( msdn 참조 ) 잘못된 생성자를 사용하고 있다는 것이 맞습니다. 지금 고칠 게요.
margnus1

FileInfo.Directory.Root어떤 종류의 파일 시스템 링크도 처리 할 수있는 것처럼 보이지 않습니다. 따라서 symlink / hardlinks / junction point 또는 NTFS가 제공하는 모든 것이없는 클래식 로컬 드라이브 문자에서만 작동합니다.
ygoe

누구든지 단계별 설명을 해 주시겠습니까? 다른 단계에서 무엇을 했습니까? 실제로 어떻게 작동하는지 이해하면 매우 도움이 될 것입니다.
bapi 2013

5
이 코드에는 네임 스페이스 System.ComponentModelSystem.Runtime.InteropServices.
Kenny Evitt 2014 년

17

위의 코드 는 클러스터 크기가 항상 0이기 때문에 Windows Server 2008 또는 2008 R2 또는 Windows 7 및 Windows Vista 기반 시스템 에서 제대로 작동하지 않습니다 ( UAC가 비활성화 된 경우에도 GetDiskFreeSpaceW 및 GetDiskFreeSpace는 -1을 반환 합니다.) 작동하는 수정 된 코드는 다음과 같습니다.

씨#

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

이 코드가 작동하려면 System.Managment 참조가 필요합니다. WMI를 제외하고 Windows (6.x 버전)에서 클러스터 크기를 정확하게 가져 오는 표준 방법이없는 것처럼 보입니다. : |
Steve Johnson

1
저는 Vista x64 컴퓨터에서 코드를 작성했고 이제 64 비트 및 WOW64 모드의 W7 x64 컴퓨터에서 테스트했습니다. GetDiskFreeSpace는 성공시 0이 아닌 값을 반환 해야 합니다 .
margnus1 2011 년

1
C #에 대한 원래 질문
Shane Courtrille 2013 년

4
이 코드는도 (한 닫는 괄호를 사용하여 누락) 컴파일하지 않고 하나의 라이너 학습 목적을 위해 매우 끔찍
미카엘 V.

1
요청할 때이 코드는 컴파일 문제를 가지고 .First()그것이 같은 IEnumerable아닌 IEnumerable<T>, 당신은 코드 첫 번째 전화 사용하려는 경우.Cast<object>()
요엘 halb

5

MSDN 소셜 포럼에 따르면 :

디스크의 크기는 파일을 저장하는 클러스터 크기의 합계 여야합니다. 클러스터 크기를 찾으려면 P / Invoke
long sizeondisk = clustersize * ((filelength + clustersize - 1) / clustersize);
들어가야 합니다. 반환합니다.GetDiskFreeSpace()

C #에서 파일의 디스크 크기를 가져 오는 방법을 참조하세요 .

그러나 압축이 켜져 있는 NTFS 에서는 작동하지 않는다는 점에 유의하십시오 .


2
압축 및 / 또는 스파 스 파일을 설명하기 GetCompressedFileSize보다는 다음과 같은 것을 사용하는 것이 좋습니다 filelength.
Hans Olsson

-1

다음과 같을 것이라고 생각합니다.

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

확인을 받기 위해 아직 테스트 중입니다.


7
이것은 파일 크기 (파일 내의 바이트 수)입니다. 실제 하드웨어의 블록 크기에 따라 파일이 더 많은 디스크 공간을 사용할 수 있습니다. 예를 들어 내 HDD의 600byte 파일은 디스크에서 4kB를 사용했습니다. 그래서이 대답은 틀 렸습니다.
0xBADF00D
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.