Você está na página 1de 6

Compactando e Descompactando com ZLib

Escrito por Marcos Rocha


Qua, 29 de Julho de 2009 00:00

Esta biblioteca está presente desde a versão 5 do Delphi e é muito útil para criar arquivos
compactados rapidamente podendo adicionar um ou mais arquivos no pacote. Aqui vamos
abordar um pouco do conceito de compactação e os resultados obtidos através da ZLib.

Conhecendo a ZLib
Pouca gente conhece o potencial que nossa ferramenta do dia a dia contém, e a ZLib é uma
delas. Desenvolvida sob a licença
GNU/GPL
a
ZLib
originalmente foi criada para utilização em sistemas operacionais baseados em
UNIX
/
Linux
e com seu código fonte em
C
, foi incluída pela equipe da
Borland
para utilização em aplicações com o
Delphi
. É uma excelente biblioteca de compactação e descompactação de um ou mais arquivos
obtendo um tamanho final muito semelhante ao dos melhores compressores do mercado, veja
a tabela comparativa abaixo.
  Compressor  Tempo GastoProporção de Compressão  Tamanho Final
 Mais usado hoje  6:25  5%  26,9Mb
 ZLib  1:50  10%  47,1Mb
Tabela 1. Comparativo entre os compressores.
Entendendo a compressão de arquivos
A compactação (ou compressão) de dados nada mais é do que um algoritmo avançado que
"agrupa" sequencias de caracteres substituindo-as por outra menor, ou seja, se o conteúdo de
um arquivo executável contém uma sequencia de cinco letras "A" seguidas (ou "AAAAA"), o
algoritmo pode substituí-las por "5A". Por isso que quando compactamos um banco de dados
ou um arquivo texto sua proporção de compressão é menor (quanto menor, melhor), pois
arquivos deste tipo contém muitos caracteres sequenciais em sua estrutura, diferentemente de
imagens bitmap ou arquivos mp3 onde quase não há caracteres sequenciais em seu conteúdo.
Compactando arquivos com a ZLib

Para compactar um ou mais arquivos com a ZLib dispomos de uma classe chamada TCompre
ssionStream
que é responsável por criar e compactar um arquivo. Seu funcionamento é simples, ela lê o
arquivo (ou lista de arquivos) indicado alocando na memória e aplica o algoritmo de

1/6
Compactando e Descompactando com ZLib

Escrito por Marcos Rocha


Qua, 29 de Julho de 2009 00:00

compressão já gravando no disco. Na instância do objeto desta classe, podemos obter dados
como tamanho total do arquivo, posição de leitura atual e proporção de compressão, além de
podermos associar um evento do tipo 
TNotifyEvent
para saber quando a compressão está em andamento.
O código abaixo demonstra o método de uso da classe TCompressionStream da ZLib para
compactação de um ou mais arquivos, para fazê-lo funcionar, coloque em um
form
os seguintes componentes: 2 Labels (
Label1
e
Label2
),
OpenDialog
e um 
Button
. Defina a opção
ofAllowMultiSelect
do
OpenDialog1
como
True
.
// Progresso da Compactação
procedure TForm1.CompressionProgress(Sender: TObject);
begin
  Label2.Caption := 'Leitura Atual: '+IntToStr((Sender as TCompressionStream).Position) +
                    ' / Taxa de Compressão: ' + CurrToStrF(100 - (Sender as
TCompressionStream).CompressionRate, ffNumber, 2);
  // Processa as mensagens do Windows na aplicação para evitar o estado "Não respondendo"
  Application.ProcessMessages;
end;

procedure TForm1.CompressFiles(Arquivos: TStrings; const Compactado: String);


var
  InFile, OutFile, TmpFile: TFileStream;
  Compr: TCompressionStream;
  I, L: Integer;
  S: String;
  ATempPath: array[0..255] of Char;
begin
  if Arquivos.Count > 0 then
  begin
    // Cria o arquivo de saída, será nosso compactado
    OutFile := TFileStream.Create(Compactado, fmCreate);
    try

2/6
Compactando e Descompactando com ZLib

Escrito por Marcos Rocha


Qua, 29 de Julho de 2009 00:00

      { Grava o número de arquivos }


      L := Arquivos.Count;
      OutFile.Write(L,SizeOf(L));
      for I := 0 to Arquivos.Count-1 do
      begin
        Label1.Caption := 'Comprimindo: '+IntToStr(I+1)+' de '+IntToStr(Arquivos.Count);
        InFile := TFileStream.Create(Arquivos[I], fmOpenRead);
        try
          { Grava o nome do arquivo a compactar }
          S := ExtractFilename(Arquivos[I]);
          L := Length(S);
          OutFile.Write(L,SizeOf(L));
          OutFile.Write(S[1],L);
          { Pega o caminho da pasta temporária do Windows }
          ATempPath := #0;
          GetTempPath(256, ATempPath);
          { Grava o tamanho do arquivo a compactar }
          L := InFile.Size;
          OutFile.Write(L,SizeOf(L));
          { Comprime o arquivo em um outro temporário }
          TmpFile := TFileStream.Create(Trim(ATempPath)+'tmpZLib',fmCreate);
          Compr := TCompressionStream.Create(clMax, TmpFile); // clMax é compressão Máxima
          Compr.OnProgress := CompressionProgress; // Atribui o evento para sabermos se a
compressão está em andamento
          try            
            Compr.CopyFrom(InFile,L); // Efetua a compressão do arquivo
          finally
            Compr.Free;
            TmpFile.Free;
          end;
          { Copia o arquivo comprimido temporário para o nosso arquivo de saída }
          TmpFile := TFileStream.Create(Trim(ATempPath)+'tmpZLib',fmOpenRead);
          try
            OutFile.CopyFrom(TmpFile,0);
          finally
            TmpFile.Free;
          end;
        finally
          InFile.Free;
        end;
      end;
      Label1.Caption := '';
      Label2.Caption := '';
    finally
      OutFile.Free;
    end;

3/6
Compactando e Descompactando com ZLib

Escrito por Marcos Rocha


Qua, 29 de Julho de 2009 00:00

    DeleteFile(Trim(ATempPath)+'tmpZLib'); // Remove o arquivo temporário


  end;
end;

procedure TForm1.Button1Click(Sender: TObject);


begin
  OpenDialog1.Execute;
  if (Trim(OpenDialog1.FileName) ‹› '') and (OpenDialog1.Files.Count › 0) then
    CompressFiles(OpenDialog1.Files,'C:Compactado.zlib');
end;

É importante salientar que uma vez compactado com a ZLib, o arquivo somente poderá
ser descompactado por ela.

Descompactando arquivos com a ZLib

A rotina de descompactação é muito parecida com a de compactação. Porém aqui temos


apenas a opção de descompactar todos os arquivos para um determinado diretório. Para quem
quiser se aventurar, é possível implementar rotinas para pular arquivos e inclusive, visualizá-los
para mostrar ao usuário qual(is) arquivo(s) ele quer extrair.
var
  nMax: Integer;
// Progresso da Descompactação
procedure TForm1.DecompressionProgress(Sender: TObject);
begin
  Label2.Caption := CurrToStrF(((Sender as TDecompressionStream).Position * 100) /
nMax,ffNumber,0);
  Application.ProcessMessages;
end;

procedure TForm1.DecompressFiles(FileName, Destination: String);


var
  InFile, OutFile: TFilestream;
  Decompr: TDecompressionStream;
  S: String;
  I,L,C: Integer;
begin
  Destination := IncludeTrailingPathDelimiter(Destination);
  InFile      := TFileStream.Create(FileName,fmOpenRead);
  try
    { Pega o número de arquivos }
    InFile.Read(C,SizeOf(C));
    for I := 1 to C do

4/6
Compactando e Descompactando com ZLib

Escrito por Marcos Rocha


Qua, 29 de Julho de 2009 00:00

    begin
      Label1.Caption := 'Descompactando: '+IntToStr(I)+' de '+IntToStr(C);
      { Pega o nome do arquivo }
      InFile.Read(L,SizeOf(L));
      SetLength(S,L);
      InFile.Read(S[1],L);
      { Lê o tamanho do arquivo }
      InFile.Read(L,SizeOf(L));
      { Progresso do arquivo atual. Não se pode ler Decompr.Size, dá erro, por isso utilizamos L }
      nMax := L;
      { Descompacta e grava o arquivo no disco }
      S := Destination+S; // Adiciona o caminho do arquivo
      OutFile := TFileStream.Create(S,fmCreate or fmShareExclusive);
      Decompr := TDecompressionStream.Create(InFile);
      Decompr.OnProgress := DecompressionProgress;
      try
        OutFile.CopyFrom(Decompr,L);
      finally
        OutFile.Free;
        Decompr.Free;
      end;
    end;
    Label1.Caption := '';
    Label2.Caption := '';
  finally
    InFile.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);


begin
  DecompressFiles('C:Compactado.zlib','C:');
end;

Conclusão

Com a ZLib, podemos obter ótimos resultados trabalhando com compactação e


descompactação de arquivos. Em uma aplicação prática do dia a dia seria muito fácil comprimir
um backup do Firebird (*.fbk) e enviá-lo por email para a equipe de suporte em
uma situação onde seja necessário trabalhar com um banco de dados real do usuário no
ambiente de desenvolvimento. Além do mais, com o menor tempo de compressão
conseguimos obter quase o mesmo resultado do software de compressão mais usado
atualmente.

5/6
Compactando e Descompactando com ZLib

Escrito por Marcos Rocha


Qua, 29 de Julho de 2009 00:00

Se preferir, faça o Download dos Fontes .

6/6

Você também pode gostar