8 Stimmen

Wie kann ich das Komprimierungsattribut einer Datei in Delphi festlegen?

Wie kann ich Dateien komprimieren (das 'c'-Attribut setzen) von Delphi aus? Ich spreche über die Funktion "Inhalt komprimieren, um Speicherplatz zu sparen", die unter NTFS verfügbar ist.

Es scheint, dass FileSetAttr es mir nicht ermöglicht, das 'c'-Attribut für eine Datei zu setzen.

7voto

RRUZ Punkte 132753

Sie können auch die CIM_DataFile und CIM_Directory WMI-Klassen verwenden, beide haben zwei Methoden namens Compress und UnCompress, die verwendet werden können, um die NTFS-Komprimierung in einer Datei oder einem Ordner festzulegen.

Überprüfen Sie diese Beispiele (wenn das der Fall ist)

Komprimieren (NTFS) oder Dekomprimieren einer Datei

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;

Komprimieren (NTFS) oder Dekomprimieren eines Ordners

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;

6voto

David Heffernan Punkte 585606

Die Dokumentation für SetFileAttributes() erklärt, dass die FILE_ATTRIBUTE_COMPRESSED Kennzeichnung von dieser Funktion nicht akzeptiert wird (obwohl sie von GetFileAttributes akzeptiert wird). Stattdessen heißt es:

Um den Komprimierungszustand einer Datei festzulegen, verwenden Sie die DeviceIoControl-Funktion mit der Operation FSCTL_SET_COMPRESSION.

Der FSCTL_SET_COMPRESSION-Link erklärt besonders genau, wie es gemacht wird. Es geht ungefähr so vor:

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;

6voto

Glenn1234 Punkte 2482

Hier ist es. Rufen Sie dies gegen eine Datei oder einen Ordner auf, und es sollte die Arbeit für Sie erledigen. State=true komprimiert es, State=false hebt die Komprimierung auf. Beachten Sie jedoch, dass wenn Sie es gegen einen Ordner ausführen, nur das Attribut geändert wird und zukünftige darin erstellte Dateien komprimiert werden. Um die bereits vorhandenen Dateien zu komprimieren, müssen Sie iterieren und dies für jede Datei aufrufen (FindFirst/FindNext/FindClose). HTH.

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 Meldung: ' + 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;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X