Recent

Author Topic: Zipper: Addition of multiple files  (Read 737 times)

dgrhoads

  • Jr. Member
  • **
  • Posts: 53
Zipper: Addition of multiple files
« on: April 14, 2026, 08:24:53 pm »
Attached is a program which attempts to load two files to a zip file in two operations.  My expectation is that at the conclusion of the process, both files would be included in the zip file.  What happens is that after I run "zipfile" the second time, only File2.txt is in the zip file.  I expected both File1.txt and File2.txt to be in the zipfile.

Is this a bug or do I have to do something more to add the second file to the zip file so it will contain two files, not just one.

dgrhoads

  • Jr. Member
  • **
  • Posts: 53
Re: Zipper: Addition of multiple files
« Reply #1 on: April 14, 2026, 08:27:25 pm »
I am running the latest version of Lazarus (4.6).

jeremiah

  • New Member
  • *
  • Posts: 23
Re: Zipper: Addition of multiple files
« Reply #2 on: April 14, 2026, 10:32:54 pm »
procedure TForm1.FormActivate(Sender: TObject);
var           
  aZip : TZipper;
  ZipName : String = 'ZipFile.zip';
  fCount  : Integer;
  fList   : TStringList;
begin
  aZip := TZipper.Create;
  fList:= TStringList.Create;
  flist.Add('File1.txt');
  flist.Add('File2.txt');
  try

    aZip.FileName:= zipName;
    azip.ZipFiles(flist);
  {  aZip.ZipFile('File1.txt');
    fCount := aZip.Files.Count;
    ShowMessage('After File1 added, fileCount: '+IntToStr(fCount));
    aZip.ZipFile('File2.txt');   
    fCount := aZip.Files.Count;
    ShowMessage('After File2 added, fileCount: '+IntToStr(fCount)); }
  finally
    aZip.Free;
    fList.Free;

  end;

end;

wp

  • Hero Member
  • *****
  • Posts: 13513
Re: Zipper: Addition of multiple files
« Reply #3 on: April 14, 2026, 11:13:48 pm »
There is a wiki article about it: https://wiki.lazarus.freepascal.org/paszlib. The basic idea is to add the individual files to the Entries of the zipper instance by calling "AddFileEntry", and then to zip the entire Entries list by calling "ZipAllFiles" (or call the convenience procedure "ZipFiles" with a StringList containing the names of all files to be zipped, as jeremiah suggested).

Here is a simplified example how to add files from a string array:
Code: Pascal  [Select][+][-]
  1. uses
  2.   ..., Zipper;
  3.  
  4. procedure ZipFiles(AZipFileName: String; const AFileNames: array of string);
  5. var
  6.   zip: TZipper;
  7.   fn: String;
  8. begin
  9.   zip :=  TZipper.Create;
  10.   try
  11.     zip.FileName := AZipFileName;
  12.     for fn in AFileNames do
  13.       zip.Entries.AddFileEntry(fn);
  14.     zip.ZipAllFiles;
  15.   finally
  16.     zip.Free;
  17.   end;
  18. end;
  19.  
  20. procedure TForm1.Button1Click(Sender: TObject);
  21. begin
  22.   ZipFiles('test.zip', ['unit1.pas', 'unit1.lfm']);
  23. end;  
« Last Edit: April 14, 2026, 11:18:46 pm by wp »

dgrhoads

  • Jr. Member
  • **
  • Posts: 53
Re: Zipper: Addition of multiple files
« Reply #4 on: April 15, 2026, 06:48:20 am »
I am well aware that if you add two files in the same operation, both files will appear in the zip file.  The problem is that if you add two files in two successive operations as is done in my example, then after the second operation, only the second file is present.

With the standalone zip software, one can add files, one at a time and have all the files present after the last addition.  An example of the need to add files at various time intervals is when a zip file is being built at the rate of one file a week.  With the current implementation of zipFile, one would have to unzip the zip file, add the new file to the list of files and reZip it with all the new files.

To me, the fundamental problem seems to be that fileZip can only create a new zip file, it cannot open an existing one.  If zipFile could open an existing zipFile, then additional files could be easily added.  The code documentation dealing with creating/opening the file specifies that is is supposed to open an existing file (Createfm), but that doesn't happen.

wp

  • Hero Member
  • *****
  • Posts: 13513
Re: Zipper: Addition of multiple files
« Reply #5 on: April 15, 2026, 04:09:52 pm »
You could try Abbrevia (available in OPM):

Code: Pascal  [Select][+][-]
  1. program AddToZip;
  2.  
  3. uses
  4.   AbZipKit, Abbrevia;
  5.  
  6. procedure AddFileToZip(const ZipFileName, FileToAdd: string);
  7. var
  8.   ZipKit: TAbZipKit;
  9. begin
  10.   ZipKit := TAbZipKit.Create(nil);
  11.   try
  12.     // Opens existing ZIP or creates a new one
  13.     ZipKit.OpenArchive(ZipFileName);
  14.  
  15.     // Add files
  16.     ZipKit.AddFiles(FileToAdd, 0);
  17.  
  18.     // Write changes
  19.     ZipKit.Save;
  20.   finally
  21.     ZipKit.Free;
  22.   end;
  23. end;
  24.  
  25. begin
  26.   AddFileToZip('test.zip', 'project1.lpi');
  27.  
  28. end.

dgrhoads

  • Jr. Member
  • **
  • Posts: 53
Re: Zipper: Addition of multiple files
« Reply #6 on: April 15, 2026, 09:42:04 pm »
Thanks.  OPM is a revelation for me.  It makes adding packages so much easier.

Is there any documentation for Abbrevia?  Or is our only recourse to read the code?

dgrhoads

  • Jr. Member
  • **
  • Posts: 53
Re: Zipper: Addition of multiple files
« Reply #7 on: April 15, 2026, 10:15:03 pm »
Documentation source:
https://sourceforge.net/projects/tpabbrevia/files/Documentation/3.04/

Abbrevia had its origin in the Delphi / C++ world.  This documentation is for non-Lazarus development environments, but it does provide numerous code exaples.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12851
  • FPC developer.
Re: Zipper: Addition of multiple files
« Reply #8 on: April 15, 2026, 10:35:15 pm »
I think you can read the compressed/stored files as streams, and store them again without recompressing. Some relevant code.

Code: Pascal  [Select][+][-]
  1.  TZipContextCollection = TObjectHashMap<string,TZipContext>;
  2.  TEPub = class
  3.                  var
  4.                  Files   : TZipContextCollection ;
  5.                  filesci : TZipContextCollection ;
  6.                  procedure DoCreateOutZipStream(Sender: TObject; var AStream: TStream;  AItem: TFullZipFileEntry);
  7.                  procedure DoDoneOutZipStream(Sender: TObject; var AStream: TStream;AItem: TFullZipFileEntry);
  8.              ....
  9.                end;
  10.  
  11. procedure TEPub.DoCreateOutZipStream(Sender: TObject; var AStream: TStream;
  12.   AItem: TFullZipFileEntry);
  13. var j: integer;
  14.     lc : string;
  15.     v : TZipContext;
  16. begin
  17.   lc:=lowercase(AItem.ArchiveFilename);
  18.   if filesci.TryGetValue(lc,v) then
  19.     writeln('warning duplicate names detected like ',AItem.ArchiveFilename);
  20.   v:=TZipContext.create;
  21.   astream:=v.strm;
  22.   v.assign(aitem);
  23.   files.add(aitem.ArchiveFileName,v);
  24.   filesci.add(lc,v);
  25. end;
  26.  
  27. procedure TEPub.DoDoneOutZipStream(Sender: TObject; var AStream: TStream;
  28.   AItem: TFullZipFileEntry);
  29. begin
  30.   AStream.Position:=0;
  31. end;
  32.  
  33. procedure TEPub.loadall;
  34. var
  35.   ZipFile: TUnZipper;
  36.   i      : Integer;
  37.  
  38. begin
  39.   files.clear; filesci.clear;
  40.   ZipFile := TUnZipper.Create;
  41.   try
  42.     ZipFile.FileName := ZipName;
  43.     zipfile.Examine;
  44.     ZipFile.OnCreateStream := DoCreateOutZipStream;
  45.     ZipFile.OnDoneStream:=DoDoneOutZipStream;
  46.     ZipFile.UnZipallFiles;
  47.   finally
  48.     ZipFile.Free;
  49.   end;
  50. end;
  51.  
  52.  

and to rezip:

Code: [Select]
procedure TEPub.zipall(const fname: string);
var FZipper:TZipper;
    v :tzipcontext;
    entry:TZipFileEntry;
begin
  FZipper:=TZipper.Create;
  try
   FZipper.FileName:=fname;
   for v in files.Values do v.done:=false;
   if files.TryGetValue('mimetype',v) then
      begin
        v.strm.Position:=0;
        entry:=FZipper.Entries.AddFileEntry(v.strm,v.name);
        entry.CompressionLevel:=clnone;
        v.done:=true;
      end;
   for v in files.Values do
      begin
        if not v.done then
          begin
            v.strm.Position:=0;
            entry:=FZipper.Entries.AddFileEntry(v.strm,v.name);
          end;
      end;
    FZipper.ZipAllFiles;
  finally
    fzipper.free;
    end;
end;

Note that this code also assures that the mimetype file is "stored" and first in the archive as per EPUB spec. It would be interesting to know if abbrevia can manipulate zip files without essentially reading/storing (or copying) them.

 

TinyPortal © 2005-2018