1

I need to extract a zip file with Delphi using the Abbrevia ABZIP module. But I would like to exclude files in the root of the zip file.

Example: my zip file contains this

myfile.txt
otherfile.txt
directory1\myfile.txt
directory2\file.txt

Now I would like to exclude \myfile.txt but include \directory1\myfile.txt

I have tried the following:

procedure unzipFiles;
var
  zp  : TAbZipKit;

const
  includepath = '*.*';
  excludepath = '\myfile.txt';  // <<< various variants of "root" tried

begin
  //
  zp := TAbZipKit.Create(nil);
  zp.OpenArchive(StartDir + '\zipfile.zip');
  zp.BaseDirectory := StartDir;
  zp.ExtractOptions := [eoCreateDirs, eoRestorePath];
  zp.ExtractFilesEx(
             includepath,
             excludepath
        );
  zp.CloseArchive;
  zp.Free;
end;

Which option am I missing to "catch" only the root location of "myfile.txt" ?

** EDIT ** : if there is a way to ONLY extract subdirectories, it would also be usable for me.

MyICQ
  • 987
  • 1
  • 9
  • 25
  • Did you try `excludepath := 'myfile.txt';`? – Olivier Mar 02 '21 at 08:38
  • @Olivier, this works, but will exclude same name in directories. – MyICQ Mar 02 '21 at 09:01
  • 2
    You could use `OnConfirmProcessItem` to skip processing of items based on custom condition written in Delphi code, e.g.: `procedure TForm1.ZipConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); begin Confirm := (Item.StoredPath <> ''); end;`. – Peter Wolf Mar 02 '21 at 09:12
  • @Peter, thank you. It may be worth mentioning that it's not possible to assign the OnConfirmProcessItem to a procedure directly. Instead, a class must be created. I have updated answer with your method as well. – MyICQ Mar 02 '21 at 09:39

1 Answers1

1

Solution found by digging into the ExtractFilesEx function. Simply use the collection FArchive and examine the properties of this.

The use the more lowlevel function ExtractAt

procedure unzipFiles;
var
  zp  : TAbZipKit;
  i   : integer; 

begin
  //
  zp := TAbZipKit.Create(nil);
  zp.OpenArchive(StartDir + '\zipfile.zip');
  zp.BaseDirectory := StartDir;
  zp.ExtractOptions := [eoCreateDirs, eoRestorePath];
 
  // ------- new 
  // examine if there is a /  in the StoredPath property
  // if blank, it's in the root.

  for i :=   0 to zp.FArchive.Count -1 do
    begin
      if   (zp.FArchive.ItemList.Items[i].StoredPath  <> '') then
        begin
          zp.ExtractAt(i, '');
        end;

    end;

(*
  zp.ExtractFilesEx(
             includepath,
             excludepath
        );
*)
  zp.CloseArchive;
  zp.Free;
end;

Solution with OnEvent handling, as per Peter Wolff

For this, a class must be added to the code.

// add these to the USES directive
uses
   AbBase, AbArcTyp, AbZipKit, Abutils;

// now add a class
type
 zip_helper = class
 public
      procedure ZipConfirmProcessItem(
                      Sender: TObject;
                      Item: TAbArchiveItem;
                      ProcessType: TAbProcessType;
                      var Confirm: Boolean);
 end;


// the class helper function could be like this:
procedure zip_helper.ZipConfirmProcessItem(
                Sender: TObject;
                Item: TAbArchiveItem;
                ProcessType: TAbProcessType;
                var Confirm: Boolean);
begin
        Confirm := (Item.StoredPath <> '');
end;


//  Now the extract from above can be changed to this:
procedure unzipDefaults;
var
  zp  : TAbZipKit;    // our zipper
  hlp: zip_helper;    // class helper

begin

  zp := nil;
  hlp := nil;
  try
          hlp := zip_helper.create;   // create the class helper
          zp := TAbZipKit.Create(nil);


          zp.OpenArchive(StartDir + '\Defaults.zip');
          zp.BaseDirectory := StartDir;
          zp.ExtractOptions := [eoCreateDirs, eoRestorePath];

           // set the event
           // 
          zp.OnConfirmProcessItem := hlp.ZipConfirmProcessItem;

          // and simply extract all
          zp.ExtractFiles('*.*');

          zp.CloseArchive;
    finally
          FreeAndNil(zp);
          freeandnil(hlp);
    end;
end;

MyICQ
  • 987
  • 1
  • 9
  • 25
  • 1
    You don't really need `zip_helper` instance to assign the event handler. You can use class methods as explained in the answer to [Handle class event with regular procedure](https://stackoverflow.com/a/11084676/11562188). Anyway, if I were you, I'd rather subclass `TAbZipKit` and introduce new `ExtractFiles` method that would take `TPredicate` as an argument. – Peter Wolf Mar 02 '21 at 11:51
  • Peter, thank you. I am on an old version of Delphi, so probably don't have this possibility. I appreciate your input for this ! – MyICQ Mar 02 '21 at 12:14