How to compress/decompress multiple files using Delphi 7?

Sometimes, Delphi 7 programmers need to implement some kind of compression/decompression features in their programs.
Imagine you need to make a backup of files, like paradox databases or making an import/export feature that needs several files.
The best way to do this is using compression tools to archive all the files into one single exportable file.

There are several ways to do this in delphi, using components that support some common compression/archiving algorithms (CAB, ZIP, ACE, TAR, etc…) that can be opened with other applications that support the same formats.

On this article we will not use any of those, and we will not need to install any component or package.
Just one function to compress and another one to decompress, really simple.

Compressing files :

procedure CompressFiles(Files : TStrings; const Filename : String);
var
 infile, outfile, tmpFile : TFileStream;
 compr : TCompressionStream;
 i,l : Integer;
 s : String;
 
begin
 if Files.Count > 0 then
 begin
 outFile := TFileStream.Create(Filename,fmCreate);
 try
 { the number of files }
 l := Files.Count;
 outfile.Write(l,SizeOf(l));
 for i := 0 to Files.Count-1 do
 begin
 infile := TFileStream.Create(Files[i],fmOpenRead);
 try
 { the original filename }
 s := ExtractFilename(Files[i]);
 l := Length(s);
 outfile.Write(l,SizeOf(l));
 outfile.Write(s[1],l);
 { the original filesize }
 l := infile.Size;
 outfile.Write(l,SizeOf(l));
 { compress and store the file temporary}
 tmpFile := TFileStream.Create('tmp',fmCreate);
 compr := TCompressionStream.Create(clMax,tmpfile);
 try
 compr.CopyFrom(infile,l);
 finally
 compr.Free;
 tmpFile.Free;
 end;
 { append the compressed file to the destination file }
 tmpFile := TFileStream.Create('tmp',fmOpenRead);
 try
 outfile.CopyFrom(tmpFile,0);
 finally
 tmpFile.Free;
 end;
 finally
 infile.Free;
 end;
 end;
 finally
 outfile.Free;
 end;
 DeleteFile('tmp');
 end;
end;

The function takes a TStrings list and the destination filename as input.

Imagine that you have a “Memo1” with various filenames, to compress them all to “c:\dest.myzip”.
Just call the function like this to compress the files :

CompressFiles(Memo1.Lines,'c:\dest.myzip');

Decompressing files :

procedure DecompressFiles(const Filename, DestDirectory : String);
var
 dest,s : String;
 decompr : TDecompressionStream;
 infile, outfile : TFilestream;
 i,l,c : Integer;
begin
 // IncludeTrailingPathDelimiter (D6/D7 only)
 dest := IncludeTrailingPathDelimiter(DestDirectory);
 
 infile := TFileStream.Create(Filename,fmOpenRead);
 try
 { number of files }
 infile.Read(c,SizeOf(c));
 for i := 1 to c do
 begin
 { read filename }
 infile.Read(l,SizeOf(l));
 SetLength(s,l);
 infile.Read(s[1],l);
 { read filesize }
 infile.Read(l,SizeOf(l));
 { decompress the files and store it }
 s := dest+s; //include the path
 outfile := TFileStream.Create(s,fmCreate);
 decompr := TDecompressionStream.Create(infile);
 try
 outfile.CopyFrom(decompr,l);
 finally
 outfile.Free;
 decompr.Free;
 end;
 end;
 finally
 infile.Free;
 end;
end;

This function takes the compressed filename and destination directory to extract the files.
Imagine you have a compressed file called “c:\compressed.myzip” and want to extract it to “D:\”.
Call the function like this :

DecompressFiles('c:\compressed.myzip','D:\');

Thats it, its the only code you need to backup/restore several files at once.

This entry was posted in Algorithms, Delphi.

20 Responses to How to compress/decompress multiple files using Delphi 7?

  1. omid says:

    Hi
    Very good. Thank you.

  2. italo says:

    Dear friend I found your tip “How to compress/decompress multiple files using Delphi 7” I coudn’t figure out how to use the TCompressionStream, can you clear it up to me.

    Thanks in advance

    italo

    • ljj748 says:

      Hi, just as below:

      uses zlib ;

      TCompressionStream and TDecompressionStream are come from Zlib unit .

  3. Marcio says:

    Hi,

    I’m from Brazil. Sorry my english.

    Works great when the file will be compressed is not in use.
    When the file is in use, the following error occurs: The file …. is being used in another process.

    And not compact.

    Please help me

  4. utoro says:

    Hi, I am from Indonesia

    Thanks a lot Hugo, these are very useful for me.

    GBU

  5. irfan says:

    it always work fine.But if i tried to compress more files, it gives error which is “Can not open file tmp”

    if you know answer, can you send mo e mail?

  6. Guilherme says:

    There is a bug on DecompressFiles method. Add: s := #0; after { read filename } to fix.

    • drschwarcz says:

      THX, I tried it, but the first filename is wrong yet. Do you have any idea?

    • drschwarcz says:

      Hi.

      I fixed my problem. As I think, the root cause that I use Delphi XE3. So, I need to change the writing/reading of Filenames.

      I anyone needs help, let me know and I will share my solution.

  7. Tom I. says:

    infile := TFileStream.Create(Filename,fmOpenRead or fmShareDenyWrite);

    … should fix the “file in use” problem.

    cheers.

  8. Tom I. says:

    To marcio:
    Sorry, error in my post – “file in use” problem was in “CompressFiles” method.

    replace
    infile := TFileStream.Create(Files[i],fmOpenRead);

    with:
    infile := TFileStream.Create(Files[i],fmOpenRead or fmShareDenyWrite);

    regards.

  9. mustafa says:

    hi
    thanks for all
    How can I set zip file size

  10. Pingback: Delphi 7 How To Program

  11. arachmadi says:

    Hi, im from indonesia
    thanks, this will fix up my question about compressing multiple files 😀

  12. Klecksmann says:

    Hi,

    that’s exactly how I had done this if I just wanted to transfer the data between two of my own software solutions (e.g. a backup file).

    But is that solution compatible to opening the resulting compressed files in a regular unzipper?
    Seeing multiple files there when opened?

  13. djamel says:

    give me the example in zip file many error in my test

  14. in delphi XE 10.2 i found error while extracting the file, the error is that extraction name = half of its actual name, for example the compressed file contains :
    project1.ass
    project2.srt

    instead of that, program will only detect the name as
    projec
    projec

    so here’s, i add some ‘tweak’ here …

    in CompressFiles function, change :
    l := Length(s);
    to :
    l := Length(s) * 2;

    then in DecompressFiles function, change :
    Setlength(s,l);
    to :
    Setlength(s;l div 2);

    idk but this will work.
    2nd solution is change the String to AnsiString, even its not tested yet, this might be simpler than the first solution above

    sorry for my bad english .