我该如何在Delphi中压缩文件(设置'c'属性)?我指的是NTFS下可用的“压缩内容以节省磁盘空间”功能。
似乎FileSetAttr不允许我为文件设置'c'属性。
我该如何在Delphi中压缩文件(设置'c'属性)?我指的是NTFS下可用的“压缩内容以节省磁盘空间”功能。
似乎FileSetAttr不允许我为文件设置'c'属性。
CIM_DataFile
和CIM_Directory
WMI类,它们都有两个名为Compress和UnCompress的方法,这些方法可用于设置文件或文件夹中的NTFS压缩。请查看以下示例(如果)。
压缩(NTFS)或解压缩文件
function CompressFile(const FileName:string;Compress:Boolean):integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_DataFile.Name="%s"',[StringReplace(FileName,'\','\\',[rfReplaceAll])]));
if Compress then
Result:=FWbemObject.Compress()
else
Result:=FWbemObject.UnCompress();
end;
压缩(NTFS)或解压缩文件夹
function CompressFolder(const FolderName:string;Recursive, Compress:Boolean):integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
StopFileName : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_Directory.Name="%s"',[StringReplace(FolderName,'\','\\',[rfReplaceAll])]));
if Compress then
if Recursive then
Result:=FWbemObject.CompressEx(StopFileName, Null, Recursive)
else
Result:=FWbemObject.Compress()
else
if Recursive then
Result:=FWbemObject.UnCompressEx(StopFileName, Null, Recursive)
else
Result:=FWbemObject.UnCompress();
end;
SetFileAttributes()
的文档说明该函数不接受FILE_ATTRIBUTE_COMPRESSED
标志(尽管GetFileAttributes()
接受)。而是指出:
FSCTL_SET_COMPRESSION链接特别详细地解释了如何执行此操作。大致过程如下:要设置文件的压缩状态,请使用DeviceIoControl函数并选择FSCTL_SET_COMPRESSION操作。
const
COMPRESSION_FORMAT_NONE = 0;
COMPRESSION_FORMAT_DEFAULT = 1;
COMPRESSION_FORMAT_LZNT1 = 2;
procedure SetCompressionAttribute(const FileName: string; const CompressionFormat: USHORT);
const
FSCTL_SET_COMPRESSION = $9C040;
var
Handle: THandle;
Flags: DWORD;
BytesReturned: DWORD;
begin
if DirectoryExists(FileName) then
Flags := FILE_FLAG_BACKUP_SEMANTICS
else if FileExists(FileName) then
Flags := 0
else
raise Exception.CreateFmt('%s does not exist', [FileName]);
Handle := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, Flags, 0);
Win32Check(Handle <> INVALID_HANDLE_VALUE);
try
if not DeviceIoControl(Handle, FSCTL_SET_COMPRESSION, @CompressionFormat, SizeOf(Comp), nil, 0, BytesReturned, nil) then
RaiseLastOSError;
finally
CloseHandle(Handle);
end;
end;
if Handle=0
部分是否正确。难道你不应该检查 INVALID_HANDLE_VALUE
吗?请参见 https://dev59.com/Nl3Va4cB1Zd3GeqPBYzk#8241115 - Günther the Beautiful这里是代码,可以用于对文件或文件夹进行压缩和解压缩。当State=true时,会进行压缩;当State=false时,会进行解压缩。需要记住的是,如果您将其应用于文件夹,则只会更改属性并使以后在该文件夹中创建的文件被压缩。要压缩已经存在于其中的文件,您需要迭代并对每个文件调用此代码(使用FindFirst/FindNext/FindClose)。祝您好运。
function CompressFile(filepath: string; state: boolean): boolean;
const
COMPRESSION_FORMAT_DEFAULT = 1;
COMPRESSION_FORMAT_NONE = 0;
FSCTL_SET_COMPRESSION: DWord = $9C040;
var
compsetting: Word;
bytesreturned: DWord;
FHandle: THandle;
begin
//if not os_is_nt then
// raise Exception.Create('A Windows NT based OS is required for this function.');
FHandle := CreateFile(PChar(filepath), GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if FHandle = INVALID_HANDLE_VALUE then
raise Exception.Create('CompressFile Message: ' + SysErrorMessage(GetLastError));
if state = true then
compsetting := COMPRESSION_FORMAT_DEFAULT
else
compsetting := COMPRESSION_FORMAT_NONE;
try
Result := DeviceIOControl(FHandle, FSCTL_SET_COMPRESSION, @compsetting,
sizeof(compsetting), nil, 0, bytesreturned, nil);
finally
CloseHandle(FHandle);
end;
end;
FILE_SHARE_READ 或 FILE_SHARE_WRITE
?为什么要指定 FILE_FLAG_BACKUP_SEMANTICS
?为什么不写成 result := DeviceIOControl
?你还应该检查 FHandle=0
,以及文件是否存在。简而言之,这段代码需要好好整理一下。 - David Heffernan