以上代码在基于Windows Server 2008或2008 R2或Windows 7和Windows Vista的系统上无法正常工作,因为群集大小始终为零(即使禁用UAC,GetDiskFreeSpaceW和GetDiskFreeSpace也会返回-1)。以下是修改后的代码。
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
5条答案
按热度按时间oo7oh9g91#
这使用了GetCompressedFileSize(如ho 1所建议的)以及GetDiskFreeSpace(如PaulStack所建议的),然而,它确实使用了P/Invoke。我只对压缩文件进行了测试,我怀疑它对碎片文件不起作用。
arknldoa2#
以上代码在基于Windows Server 2008或2008 R2或Windows 7和Windows Vista的系统上无法正常工作,因为群集大小始终为零(即使禁用UAC,GetDiskFreeSpaceW和GetDiskFreeSpace也会返回-1)。以下是修改后的代码。
C#
VB.NET语言
wz8daaqr3#
根据MSDN社交论坛:
磁盘上的大小应该是存储文件的群集大小的总和:
long sizeondisk = clustersize * ((filelength + clustersize - 1) / clustersize);
您需要查看P/Invoke以找到集群大小;
GetDiskFreeSpace()
将返回它。参见 * How to get the size on disk of a file in C# *。
但是请注意,这在NTFS中是不起作用的,因为NTFS中压缩是打开的。
smtd7mpg4#
如果从kernal32.dll调用外部函数GetCompressedFileSizeW,则不需要知道块大小。该函数将始终返回块大小的倍数。
唯一需要块大小的情况是,您尝试手动计算磁盘上未压缩/稀疏的文件的大小,并且您只知道文件的 * 长度 *。然后,您可以使用
long sizeondisk = clustersize * ((filelength + clustersize - 1) / clustersize)
手动计算磁盘上的大小(如果filelengthmodblocksize不等于0,则实质上是向上舍入到blocksize的下一个倍数)。GetCompressedFileSizeW不需要此公式,根据Microsoft文档,该函数返回用于 * 存储 * 文件的字节大小。我已经用稀疏文件和压缩文件对此进行了测试,上面的代码总是返回与资源管理器报告的磁盘大小相同的大小。
cfh9epnr5#
我想会是这样的:
我还在做一些测试,以得到确认。