Compactar com zLib

Delphi

22/03/2005

Galera alguem sabe como compactar mais de um arquivo juntando em apenas um usando zLib.pas?
Valew..


Madrick

Madrick

Curtidas 0

Respostas

Madrick

Madrick

22/03/2005

Galera ninguem tem uma ideia naum?


GOSTEI 0
Madrick

Madrick

22/03/2005

Galera, como não consegui resposta para minha duvida, eu acho que consegui compactar mais de um arquivo com o zlib, ficou tipo assim:
procedure TForm1.Button1Click(Sender: TObject);
var
FileIni,FileIni2, FileOut: TFileStream;
Zip: TCompressionStream;
begin
FileIni := TFileStream.Create(´C:\Delivery\arquivo1´, fmOpenRead and fmShareExclusive);
FileIni2 := TFileStream.Create(´C:\Delivery\arquivo2, fmOpenRead and fmShareExclusive);

FileOut:=TFileStream.Create(´C:\Delivery\ArqCompact.arq´, fmCreate or fmShareExclusive);


Zip:=TCompressionStream.Create( clMax, FileOut);
Zip.CopyFrom(FileIni, FileIni.Size);
//Zip.CopyFrom(FileIni2, FileIni2.Size);
Zip.Free;
FileOut.Free;
FileIni.Free;
end;

Bom, agora como fazer para esta jossa descompactar os arquivos, separadamente,tipo retornar arquivo1, arquivo2?
Valew


GOSTEI 0
Marcelo Saviski

Marcelo Saviski

22/03/2005

Tente ´marcar´ onde começa e onde termina um arquivo, um cabeçalho de arquivo, nesse formato (não compilavel)

  TMeuZip = packed record
   NumArquivos: Integer;
   Arquivos: array[1..NumArquivos] of packed record
       Len: Integer; //Tamanho FileInName
       FileInName: string[Len]; //Armazena o nome do Arquivo
       FileSize: Integer; //Tamanho em Bytes do Arquivo
       Arquivo: array[1..Filesize] of Byte; //Arquivo Armazenado
       Fim: Byte = 0; //indica um fim do arquivo, só para verificação
  end;



O Código da compressão ficou assim:

procedure Comprimir(FileOutName: TFileName; Files: array of TFileName);
var
  FileInName: TFileName;
  FileIn, FileOut: TFileStream;
  Zip: TCompressionStream;
  NumArquivos, I, Len: Integer;
begin
  FileOut := TFileStream.Create(FileOutName, fmCreate or fmShareExclusive);
  Zip := TCompressionStream.Create( clMax, FileOut);
  NumArquivos := Length(Files);
  Zip.Write(NumArquivos, SizeOf(Integer));
  try
    for I := Low(Files) to High(Files) do
    begin
      FileIn := TFileStream.Create(Files[I], fmOpenRead and fmShareExclusive);
      try
        FileInName := ExtractFileName(Files[I]);
        Len := Length(FileInName);
        Zip.Write(Len, SizeOf(Integer));
        Zip.Write(FileInName[1], Len);
        Zip.Write(FileIn.Size, SizeOf(Integer));
        Zip.CopyFrom(FileIn, FileIn.Size);
        Zip.Write(0, 1);
      finally
        FileIn.Free;
      end;
    end;
  finally
   Zip.Free;
   FileOut.Free;
  end;
end;


Agora vc chama ele passando o Nome de um Arquivo Destino e um array de Arquivos Fontes.

Comprimir(´C:\Delivery\ArqCompact.arq´, [´C:\Delivery\arquivo1´, ´C:\Delivery\arquivo2´]);


Para descompactar,, usando o TDecompressionStream, vc 1º leria um Integer N que informaria o nº de Arquivos comprimidos, depois passaria um loop para descarregar cada um destes N Arquivos, então vc leria outro inteiro que informaria quantos caracteres tem o nome original do arquivo, Alocaria espaço em uma string S com o [color=green:17fc05ab47]SetLength(NomeOriginalArq, NumCaracteres)[/color:17fc05ab47] e leria X bytes (X = nº caracteres) em NomeOriginalArq[1].
Depois leria outro Inteiro X que indicaria o tamanho do Arquivo (descomprimido), então descarregaria esses X Bytes no Arquivo S, por fim, leria mais 1 byte, e verificaria se ele é 0, para fins de verificação.
repita isso N vezes, até que todos os arquivos estejam extraidos.

para descomprimir vai ser sua tarefa fazer. :wink:

PS: eu nunca usei a ZLib antes, então talvez vc tenha que corrigir o código antes, por favor faça isso :)
PS2:Usei a Zlib que encontrei [url=http://www.koders.com/delphi/fidCCBD2263A7E1FD209D24E2924272520B32EF7B05.aspx?s=zlib]aqui[/url], espero que seja a mesma que vc usa
PS3: Não testei.


GOSTEI 0
Madrick

Madrick

22/03/2005

Mano valew vou fazer um teste e dou retorno, T+ :?


GOSTEI 0
Madrick

Madrick

22/03/2005

rpz a que eu entedi a logica em si, mas o lance que naum estou enchegando onde esta o erro as linhas de vermelho no codigo de compactação:
try
FileInName := ExtractFileName(Files[I]);
Len := Length(FileInName);
Zip.Write(Len, SizeOf(Integer));
Zip.Write(FileIn.Size,SizeOf(Integer)); [color=red:fc38836f4a]Erro : variable requered[/color:fc38836f4a]
Zip.CopyFrom(FileIn, FileIn.Size);
Zip.Write(FileInName[1], Len);
Zip.Write(0, 1); [color=red:fc38836f4a]Erro : variable requered[/color:fc38836f4a]
finally
FileIn.Free;
E quanto a descompactação naum saquei muito bem como pegar a informação do arquivo para saber quantos arquivos foram compactado, alguem tem mais uma ideia?


GOSTEI 0
Marcelo Saviski

Marcelo Saviski

22/03/2005

Ha...

então tem que declarar as variaveis, pensei que era só quando era pra ler os valores

poem lá aonde tá:
[color=green:957f6748e6]NumArquivos, I, Len: Integer; [/color:957f6748e6]
troca por:
[color=green:957f6748e6]NumArquivos, I, Len, Size: Integer;
Fim: Byte[/color:957f6748e6]

e aonde deu erro: mude para:

Size := FileIn.Size;
Zip.Write(Size, SizeOf(Integer));


Fim := 0;
Zip.Write(Fim, SizeOf(Byte));


Para descomparctar, use como base o código que compacta, mas altere para ao invés de escrever os valores, carregue eles nas variaveis


GOSTEI 0
Madrick

Madrick

22/03/2005

Fiz uma função para tentar descomprimir o arquivo e usando o camando ´Read´ consegui capturar aqu quantidade de itens compactados, o tamanho do nome, o tamanho do arquivo mas na hora de pegar no nome do arquivo eu mando o read movendo o conteudo para uma string tipo:
zip.read(Nome, Len) onde len é o tamanho do nome visto acima;
ai ele retorna vazio inaccessible value;
Alguem tem alguma ideia do que pode ser isto;
Obs.: a compactação segue como no modelo pelo marcelo.


GOSTEI 0
Madrick

Madrick

22/03/2005

Galera esta parada tá me deixando de cabelo em pé, já passou ser uma questão de honra fazer um programa que funcione com o zlib.
Estou aberto a sugestões. :D


GOSTEI 0
Madrick

Madrick

22/03/2005

Galera sei que estou enchedo o saco com este post, mas não posso deixar esta parada passar em branco, até que me caia um raio na cabeça ou uma alma caridosa me ajude a encontrar uma solução.Descupas.. :lol:


GOSTEI 0
Madrick

Madrick

22/03/2005

Galera ninguem tem mais nenhuma ideia?


GOSTEI 0
Nerdex

Nerdex

22/03/2005

Procure por este arquivo..:[color=green:940e07f001] 21894_a_single_unit_adding_zip_file_handling_to_delphi_1.1.zip[/color:940e07f001] no Code Central do Delphi e preste atenção nisso..:

[color=red:940e07f001]CommonFileHeader[/color:940e07f001]

Segue code preview...
procedure TZipFile.SaveToFile(const filename: string);
var
  ZipFileStream: TFileStream;
  i: integer;
begin
  ZipFileStream := TFileStream.Create(filename, fmCreate);
  try
    for i := 0 to High(Files) do
      with Files[i] do
      begin
        CentralDirectory[i].RelativeOffsetOfLocalHeader :=
          ZipFileStream.Position;
        ZipFileStream.Write(LocalFileHeaderSignature, 4);
        if (LocalFileHeaderSignature = ($04034B50)) then
        begin
          ZipFileStream.Write(CommonFileHeader, SizeOf(CommonFileHeader));
          ZipFileStream.Write(PChar(filename)^,
            CommonFileHeader.FilenameLength);
          ZipFileStream.Write(PChar(extrafield)^,
            CommonFileHeader.ExtraFieldLength);
          ZipFileStream.Write(PChar(CompressedData)^,
            CommonFileHeader.CompressedSize);
        end;
      end;

    EndOfCentralDirectory.OffsetOfStartOfCentralDirectory :=
      ZipFileStream.Position;

    for i := 0 to High(CentralDirectory) do
      with CentralDirectory[i] do
      begin
        ZipFileStream.Write(CentralFileHeaderSignature, 4);
        ZipFileStream.Write(VersionMadeBy, 2);
        ZipFileStream.Write(CommonFileHeader, SizeOf(CommonFileHeader));
        ZipFileStream.Write(FileCommentLength, 2);
        ZipFileStream.Write(DiskNumberStart, 2);
        ZipFileStream.Write(InternalFileAttributes, 2);
        ZipFileStream.Write(ExternalFileAttributes, 4);
        ZipFileStream.Write(RelativeOffsetOfLocalHeader, 4);
        ZipFileStream.Write(PChar(filename)^, length(filename));
        ZipFileStream.Write(PChar(extrafield)^, length(extrafield));
        ZipFileStream.Write(PChar(fileComment)^, length(fileComment));
      end;
    with EndOfCentralDirectory do
    begin
      EndOfCentralDirSignature := $06054B50;
      NumberOfThisDisk := 0;
      NumberOfTheDiskWithTheStart := 0;
      TotalNumberOfEntriesOnThisDisk := High(Files) + 1;
      TotalNumberOfEntries := High(Files) + 1;
      SizeOfTheCentralDirectory :=
        ZipFileStream.Position - OffsetOfStartOfCentralDirectory;
      ZipfileCommentLength := length(ZipFileComment);
    end;
    ZipFileStream.Write(EndOfCentralDirectory, SizeOf(EndOfCentralDirectory));
    ZipFileStream.Write(PChar(ZipFileComment)^, length(ZipFileComment));
  finally
    ZipFileStream.Free;
  end;

end;


Autores:

// Nick Naimo <nick@naimo.com> added support for folders on 6/29/2004 (see ´NJN´)
// Marcin Wojda <Marcin@sacer.com.pl> added exceptions and try finally blocks

p.s.: se não achar te mando por e-mail


GOSTEI 0
Marcelo Saviski

Marcelo Saviski

22/03/2005

Veja se isso funciona:

procedure Descomprimir(ZipFileName: TFileName; OutDir: string);
resourcestring
  EDecompressionErrorMessage = ´Arquivo ¬s corrompido´;
var
  FileOutName: string;
  FileIn, FileOut: TFileStream; 
  Zip: TDecompressionStream;
  NumArquivos, I, Len, Size: Integer;
  Fim: Byte;
begin 
  FileIn := TFileStream.Create(ZipFileName, fmOpenRead and fmShareExclusive);
  Zip := TDecompressionStream.Create(FileIn);
  Zip.Read(NumArquivos, SizeOf(Integer));
  try
    for I := 0 to NumArquivos - 1 do
    begin
        Zip.Read(Len, SizeOf(Integer));
        SetLength(FileOutName, Len);
        Zip.Read(FileOutName[1], Len);
        Zip.Read(Size, SizeOf(Integer));
        FileOut := TFileStream.Create(IncludeTrailingBackslash(OutDir) + FileOutName, fmCreate or fmShareExclusive);
        try
          FileOut.CopyFrom(Zip, Size);
        finally
          FileIn.Free;
        end;
        Zip.Read(Fim, SizeOf(Byte));
        if Fim <> 0 then
          raise Exception.CreateFmt(EDecompressionErrorMessage, [ZipFileName]);
    end; 
  finally 
   Zip.Free; 
   FileIn.Free;
  end; 
end;


Exemplo:
Descomprimir(´ArquivoComprimido´, ´DiretórioDestino´);
Descomprimir(´C:\Arquivo.arq´, ´C:\ArquivoDescomprimido);



GOSTEI 0
Madrick

Madrick

22/03/2005

Grande Marcelo Saviski, valew pela dica acredito que é isto mesmo, vou fazer um teste para conferir, sabado eu consegui fazer a descompactação e parece estar bem similar a sua, mas de toda forma, valew pela atenção. :D


GOSTEI 0
Marcelo Saviski

Marcelo Saviski

22/03/2005

vc pode enfeitar mais isso se quiser, tipo colocar mais detalhes sobre os arquivos, ou no incio uma espécie de ponteiro para o inicio dos arquivos na stream, assim cv poderia descompactar um arquivo especifico sem ter que descompactar todos.

Desse do BDN que o Nerdex falou, parece que tem bastante coisa lá, [url=http://cc.borland.com/search/results.aspx?keywords=zlib&prod=1&cat=4¬2c12¬2c14¬2c13¬2c2¬2c3¬2c16¬2c10¬2c15¬2c17¬2c11¬2c18¬2c9¬2c1]link[/url]


GOSTEI 0
Madrick

Madrick

22/03/2005

FileOut.CopyFrom(Zip, Size);
Esta forma esta acarretando um erro na seguinte linha:
Zip.Read(Fim, SizeOf(Byte));
Nesta linha que captura o dig. verificador está dando um erro de memoria muito louco, já fiz uns teste aqui mais naum identifiquei o porque, no meu codigo tinha ficado assim :
Zip.Read(Buf ,Size);
FileOut.Write(Buf, Size);
Zip.Read(Fim, SizeOf(Byte));
onde buf é um array do tipo Byte.
O problema que este tipo de implementação acarreta fica por conta do tamanho do array, que nã pode ser menor que o tamanho do arquivo a ser descompactado.
Valew. :wink:


GOSTEI 0
POSTAR