How can I compact files (set the 'c' attribute) from Delphi? I am speaking about the "compress contents to save disk space" function available under NTFS.
It seems that FileSetAttr does not allow me to set the 'c' attribute for a file.
The documentation for SetFileAttributes()
explains that the FILE_ATTRIBUTE_COMPRESSED
flag is not accepted by that function (although it is for GetFileAttributes)
. Instead it states:
To set a file's compression state, use the DeviceIoControl function with the FSCTL_SET_COMPRESSION operation.
The FSCTL_SET_COMPRESSION link in particular explains precisely how to do it. It goes something like this:
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;