Artigo Clube Delphi 94 - Streams

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (1)  (0)

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

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

 

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.

 

Criando um exemplo completo de compactação

"

A exibição deste artigo foi interrompida :(
Este post está disponível para assinantes MVP

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?