Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi “我如何查询?”;“磁盘上的大小”;文件信息?_Delphi_Winapi_Filesystems - Fatal编程技术网

Delphi “我如何查询?”;“磁盘上的大小”;文件信息?

Delphi “我如何查询?”;“磁盘上的大小”;文件信息?,delphi,winapi,filesystems,Delphi,Winapi,Filesystems,我想为任何给定文件重现Windows资源管理器->属性对话框->常规属性页中显示的行为。具体来说,我想重现“磁盘上的大小”字段的确切值。您可以使用该函数获取结构,其CompressedFileSize字段是您需要的值(与GetCompressedFileSize返回的值相同)。正如其他人所说,您需要使用GetFileInformationByHandleEx,但看起来你需要使用或。您想要的信息在每个的AllocationSize成员中返回,但第二个是目录句柄,用于列出目录中的文件,而不是目录本身

我想为任何给定文件重现Windows资源管理器->属性对话框->常规属性页中显示的行为。具体来说,我想重现“磁盘上的大小”字段的确切值。

您可以使用该函数获取结构,其
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;