Delphi “我如何查询?”;“磁盘上的大小”;文件信息?
我想为任何给定文件重现Windows资源管理器->属性对话框->常规属性页中显示的行为。具体来说,我想重现“磁盘上的大小”字段的确切值。您可以使用该函数获取结构,其Delphi “我如何查询?”;“磁盘上的大小”;文件信息?,delphi,winapi,filesystems,Delphi,Winapi,Filesystems,我想为任何给定文件重现Windows资源管理器->属性对话框->常规属性页中显示的行为。具体来说,我想重现“磁盘上的大小”字段的确切值。您可以使用该函数获取结构,其CompressedFileSize字段是您需要的值(与GetCompressedFileSize返回的值相同)。正如其他人所说,您需要使用GetFileInformationByHandleEx,但看起来你需要使用或。您想要的信息在每个的AllocationSize成员中返回,但第二个是目录句柄,用于列出目录中的文件,而不是目录本身
CompressedFileSize
字段是您需要的值(与GetCompressedFileSize
返回的值相同)。正如其他人所说,您需要使用GetFileInformationByHandleEx
,但看起来你需要使用或。您想要的信息在每个的AllocationSize
成员中返回,但第二个是目录句柄,用于列出目录中的文件,而不是目录本身(注意:不是递归的,只是顶级的)。为了方便起见,FILE\u STANDARD\u INFO
有一个目录
布尔值,如果您不确定,请先调用它。根据文件\u ID\u双方\u DIR\u INFO
的文档
分配
包含指定为文件分配多少空间的值,以字节为单位。此值通常是底层物理设备的扇区或群集大小的倍数
这似乎为您提供了磁盘上的大小
信息
我还没有找到文件ID\u BOTH\u DIR\u INFO
结构的Delphi翻译。困难似乎在于最后一个成员,WCHAR FileName[1]
,它被描述为:
文件名[1]包含文件名字符串的第一个字符。这之后是内存中字符串的剩余部分 我不确定在Delphi中如何处理这个问题。的文章介绍了如何计算这个值。最相关的一段指出: 磁盘上的大小测量更为复杂。如果驱动器支持压缩(由Get-Volume-Information函数返回的FILE-FILE-compression标志报告),并且文件是压缩的或稀疏的(FILE-ATTRIBUTE-compressed,FILE-ATTRIBUTE-sparse-FILE),则文件的磁盘大小是Get-compressed-FILE-Size函数报告的值。这将报告文件的压缩大小(如果已压缩)或文件大小减去已取消提交且逻辑上被视为零的部分(如果稀疏)。如果文件既不是压缩的也不是稀疏的,那么磁盘上的大小就是Find-First-file函数报告的文件大小,四舍五入到最近的集群
根据David从Raymond文章中摘录的内容发布一个例程。 请随意改进它
uses
System.SysUtils, Windows;
function GetClusterSize(Drive: String): integer;
var
SectorsPerCluster, BytesPerSector, dummy: Cardinal;
begin
SectorsPerCluster := 0;
BytesPerSector := 0;
GetDiskFreeSpace(PChar(Drive), SectorsPerCluster, BytesPerSector, dummy, dummy);
Result := SectorsPerCluster * BytesPerSector;
end;
function FindSizeOnDisk(Drive: String; AFilename: string): Int64;
var
VolumeSerialNumber: DWORD;
MaximumComponentLength: DWORD;
FileSystemFlags: DWORD;
HighSize: DWORD;
FRec: TSearchRec;
AClusterSize: integer;
AFileSize, n: Int64;
begin
Result := 0;
Drive := IncludeTrailingPathDelimiter(ExtractFileDrive(Drive));
GetVolumeInformation( PChar(Drive), nil, 0, @VolumeSerialNumber,
MaximumComponentLength, FileSystemFlags, nil, 0);
if ((FileSystemFlags AND FILE_FILE_COMPRESSION) <> 0) AND
((FileSystemFlags AND (FILE_VOLUME_IS_COMPRESSED OR
FILE_SUPPORTS_SPARSE_FILES)) <> 0) then
begin // Compressed or Sparse disk
Result := GetCompressedFileSize(PChar(AFilename), @HighSize);
// Not sure if this is correct on a sparse disk ??
end
else
begin
if (System.SysUtils.FindFirst(AFilename, faAnyFile, FRec) = 0) then
begin
AFileSize := FRec.Size;
AClusterSize := GetClusterSize(Drive);
n := AFileSize mod AClusterSize;
if n > 0 then // Round up to nearest cluster size
Result := AFileSize + (AClusterSize - n)
else
Result := AFileSize;
System.SysUtils.FindClose(FRec);
end;
end;
end;
使用
System.SysUtils,Windows;
函数GetClusterSize(驱动器:字符串):整数;
变量
SectorsPerCluster,BytesPerSector,虚拟:基数;
开始
SectorsPerCluster:=0;
BytePersector:=0;
GetDiskFreeSpace(PChar(驱动器)、扇区PerCluster、BytePersector、dummy、dummy);
结果:=SectorsPerCluster*BytesPerSector;
结束;
函数FindSizeOnDisk(驱动器:String;文件名:String):Int64;
变量
卷序号:DWORD;
最大组件长度:DWORD;
文件系统标志:DWORD;
高尺寸:DWORD;
FRec:Tsarchrec;
AClusterSize:整数;
AFileSize,n:Int64;
开始
结果:=0;
驱动器:=包含RailingPathDelimiter(提取文件驱动器(驱动器));
获取卷信息(PChar(驱动器)、零、0、@VolumeSerialNumber、,
MaximumComponentLength,FileSystemFlags,nil,0);
if((FileSystemFlags和FILE\u FILE\u COMPRESSION)0)和
((文件系统标志和(文件卷)已压缩或
文件\u支持\u稀疏文件(0)然后
开始//压缩或稀疏磁盘
结果:=GetCompressedFileSize(PChar(AFilename),@HighSize);
//不确定这在稀疏磁盘上是否正确??
结束
其他的
开始
如果(System.SysUtils.FindFirst(AFilename,faAnyFile,FRec)=0),则
开始
AFileSize:=固定尺寸;
AClusterSize:=GetClusterSize(驱动器);
n:=文件大小mod AClusterSize;
如果n>0,则//四舍五入到最接近的群集大小
结果:=AFileSize+(AClusterSize-n)
其他的
结果:=文件大小;
System.SysUtils.FindClose(FRec);
结束;
结束;
结束;
由于将返回任何卷类型的正常/压缩/备用文件的实际大小,您可以依靠此函数返回磁盘上的文件大小(Windows资源管理器将此值显示为卷群集大小的系数),并使用此函数获取文件大小
从MSDN文档中关于GetCompressedFileSize
:
如果文件不在支持压缩或压缩的卷上
稀疏文件,或者如果文件未压缩或为稀疏文件,则
获取的值是实际文件大小,与返回的值相同
通过调用GetFileSize
因此,逻辑由以下代码描述(在Windows XP上使用FAT32/FAT/CDfs文件进行测试):
procedure FileSizeEx(const文件名:string;out大小,sizenodisk:UINT);
变量
驱动器:字符串;
文件句柄:THandle;
宗派,
BytesPerSector,
假人:德沃德;
集群规模:德沃德;
SizeHigh,SizeLow:DWORD;
开始
断言(FileExists(FileName));
驱动器:=IncludeTrailingPathDelimiter(提取文件驱动器(文件名));
如果没有获取DiskFreeSpace(PChar(驱动器)、SectorsPerCluster、BytesPerSector、Dummy、Dummy),则
赖斯·塞罗;
ClusterSize:=扇区perCluster*字节perSector;
FileHandle:=创建文件(PChar(文件名),0,文件共享读取或文件共享写入或文件共享删除,
零,开放的,0,0);
如果(FileHandle=INVALID\u HANDLE\u值),则
赖斯·塞罗;
尝试
SizeLow:=Windows.GetFileSize(FileHandle,@SizeHigh);
如果(GetLastError NO\u ERROR)和(SizeLow=无效的\u文件\u大小),则
赖斯·塞罗;
尺寸:=UINT(尺寸高shl 32或尺寸低);
最后
如果(FileHandle无效\u HANDLE\u值),则
CloseHandle(FileHandle);
结束;
SizeLow:=GetCompressedFileSize(PChar(文件名),@SizeHigh);
如果(GetLastError无错误)和(SizeLow=无效的文件大小)
procedure FileSizeEx(const FileName: string; out Size, SizeOnDisk: UINT);
var
Drive: string;
FileHandle: THandle;
SectorsPerCluster,
BytesPerSector,
Dummy: DWORD;
ClusterSize: DWORD;
SizeHigh, SizeLow: DWORD;
begin
Assert(FileExists(FileName));
Drive := IncludeTrailingPathDelimiter(ExtractFileDrive(FileName));
if not GetDiskFreeSpace(PChar(Drive), SectorsPerCluster, BytesPerSector, Dummy, Dummy) then
RaiseLastOSError;
ClusterSize := SectorsPerCluster * BytesPerSector;
FileHandle := CreateFile(PChar(FileName), 0, FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
nil, OPEN_EXISTING, 0, 0);
if (FileHandle = INVALID_HANDLE_VALUE) then
RaiseLastOSError;
try
SizeLow := Windows.GetFileSize(FileHandle, @SizeHigh);
if (GetLastError <> NO_ERROR) and (SizeLow = INVALID_FILE_SIZE) then
RaiseLastOSError;
Size := UINT(SizeHigh shl 32 or SizeLow);
finally
if (FileHandle <> INVALID_HANDLE_VALUE) then
CloseHandle(FileHandle);
end;
SizeLow := GetCompressedFileSize(PChar(FileName), @SizeHigh);
if (GetLastError <> NO_ERROR) and (SizeLow = INVALID_FILE_SIZE) then
RaiseLastOSError;
SizeOnDisk := UINT(SizeHigh shl 32 or SizeLow);
if (SizeOnDisk mod ClusterSize) > 0 then
SizeOnDisk := SizeOnDisk + ClusterSize - (SizeOnDisk mod ClusterSize);
end;