Как я могу сжать файлы (установить атрибут «c») из Delphi? Я говорю о функции «сжать содержимое для экономии места на диске», доступной в NTFS.
Кажется, что FileSetAttr не позволяет мне установить атрибут 'c' для файла.
Как я могу сжать файлы (установить атрибут «c») из Delphi? Я говорю о функции «сжать содержимое для экономии места на диске», доступной в NTFS.
Кажется, что FileSetAttr не позволяет мне установить атрибут 'c' для файла.
В документации для SetFileAttributes()
поясняется, что флаг FILE_ATTRIBUTE_COMPRESSED
не принимается этой функцией (хотя он для GetFileAttributes)
. Вместо этого он указывает:
Чтобы установить степень сжатия файла, используйте DeviceIoControl. с помощью FSCTL_SET_COMPRESSION а> операция.
Ссылка 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
? См. stackoverflow.com/a/8241115 ????
- person Günther the Beautiful; 27.06.2019
System.Comp
- person David Heffernan; 27.06.2019
вы также можете использовать CIM_DataFile
и CIM_Directory
классов WMI, оба имели два метода с именем Сжатие и 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;
Ну вот. Вызовите это для файла или папки, и он сделает эту работу за вас. 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 or FILE_SHARE_WRITE
? Почему вы указываете FILE_FLAG_BACKUP_SEMANTICS
? Почему бы тебе не написать result := DeviceIOControl
? Вы также должны проверить наличие FHandle=0
. А также для файла, который не существует. Короче говоря, это может быть связано с хорошей уборкой.
- person David Heffernan; 10.08.2011
FILE_FLAG_BACKUP_SEMANTICS
. В документах CreateFile
говорится, что вы должны установить этот флаг, чтобы получить дескриптор каталога. Я этого не знал. Меня все еще интересует, как система может сжимать файл, одновременно позволяя другим процессам записывать в него.
- person David Heffernan; 10.08.2011