Esse artigo faz parte da revista Clube Delphi edição 94. Clique aqui para ler todos os artigos desta edição

imagem

Clique aqui para ler essa revista em PDF.imagem_pdf.jpg

 

Expert

Streams

Implemente compactação, download em múltiplos pacotes e resources em suas aplicações com técnicas avançadas de Streams – Parte 2

 

Na edição anterior, iniciamos a criação de uma aplicação que faz uso intensivo de streams (Edição 93), que implementa compactação, download em múltiplos pacotes e resources. Desta vez, utilizaremos um stream temporário para escrever o arquivo que estamos lendo. Note que estamos utilizando GetDestStream e CleanDestStream para isso (vpeja última listagem da edição anterior). Portanto, poderemos estender essa classe futuramente para gerar a saída em um stream qualquer, não só em arquivos. Seguem suas implementações (não se esqueça da diretiva virtual neles. Veja na Listagem 1 a implementação das funções GetDestStream e CleanDestStream.

 

Listagem 1. Métodos GetDestStream e CleanDestStream

 

function TCompressor.GetDestStream(const DestFilePath:

  string): TStream;

begin

  Result := TFileStream.Create(DestFilePath,

    fmCreate);

end;

procedure TCompressor.CleanDestStream(const

  DestStream: TStream);

begin

  DestStream.Free;

end;

 

Seu funcionamento também é básico: descartamos do arquivo Index – 1 entradas para posicionar o cursor do stream de leitura; depois lemos o tamanho do nome, o nome e o tamanho do arquivo, também para posicionar o cursor; e, finalmente, lemos o conteúdo do arquivo através de um CopyFrom do stream temporário.

Na Listagem 2 podemos ver a implementação de outro método importante, ReadEntry. Estamos apenas lendo uma entrada e descartando-a caso WriteResult seja false. Para finalizar, vejamos o método Delete descrito na Listagem 3.

 

Listagem 2. Método ReadEntry

 

procedure TCompressor.ReadEntry(WriteResult:

  Boolean);

var

  Buffer: TBuffer;

  NameLength: Integer;

begin

  FStreamRead.Read(Buffer, 4);

  if WriteResult then

    FStreamWrite.Write(Buffer, 4);

  NameLength := BinToInt(CopyFromBuffer(Buffer, 4));

  FStreamRead.Read(Buffer, NameLength);

  if WriteResult then

    FStreamWrite.Write(Buffer, NameLength);

 

  FStreamRead.Read(Buffer, 8);

  if WriteResult then

    FStreamWrite.Write(Buffer, 8);

  ReadFile(BinToInt64(CopyFromBuffer(Buffer, 8)), WriteResult);

end;

 

Listagem 3. Método Delete

 

procedure TCompressor.Delete(Index: Integer);

var

  i: Integer;

  ATempStream: TFileStream;

begin

  RestartStream(fmOpenRead);

  try

    ATempStream := TFileStream.Create(FFilePath + '.tmp', fmCreate);

    try

      FStreamWrite := TCompressionStream.Create(clMax, ATempStream);

      FStreamRead := TDecompressionStream.Create(FInternalStream);

 

      for i := 0 to Index - 1 do

        ReadEntry(True);

      ReadEntry(False);

      CopyEntireStream;

    finally

      CloseStreams;

      ATempStream.Free;

    end;

  finally

    CloseStreams;

  end;

 

  DeleteFile(FFilePath);

  RenameFile(FFilePath + '.tmp', FFilePath);

 

  RestartStream(fmOpenRead);

  FStreamRead := TDecompressionStream.Create(FInternalStream);

  try

    PopulateEntries;

  finally

    CloseStreams;

  end;

end;

 

Este é provavelmente o método mais complicado da classe. Vamos precisar de um stream temporário que será, na verdade, o mesmo arquivo final, só que sem o arquivo deletado. Tivemos de fazer isso porque, ao deletarmos o arquivo no mesmo stream, depois não conseguimos reduzir o seu size para o tamanho novo (menor). Esse é o comportamento padrão de um TCompressionStream.

O primeiro passo será então copiar para este arquivo novo todas as entradas até a de número Index (ReadEntry(True)). Depois ignoramos uma entrada (ReadEntry(False)) e copiamos o resto do arquivo (CopyEntireStream). Em seguida, substituímos o arquivo final atual pelo novo e repopulamos as entradas, pois estas foram modificadas.

Pronto. Isso é tudo o que precisávamos para termos uma classe totalmente funcional com compactação para múltiplos arquivos. Agora precisamos construir uma interface com o usuário.

...

Quer ler esse conteúdo completo? Tenha acesso completo