Há alguns dias fui surpreendido com uma pergunta bem interessante sobre FMX de um aluno em um grupo. Fiquei intrigado com a pergunta porque nunca havia precisado de tal implementação em meus treinamentos ou aplicativos que desenvolvo, apesar de acreditar ser totalmente possível.
Como compactar arquivos no Android?
No Delphi possuímos classes de compactação de arquivos como a TZipFile o que era de se esperar. Por isso a possibilidade de fazer uso delas em FMX é totalmente racional. Então decidi montar um pequeno exemplo onde isso é possível. Espero que goste do tutorial.
Construindo a aplicação
O primeiro passo, evidentemente, é começar criar uma nova aplicação no Firemonkey seguindo a opção File > New > Multi-Device Application Delphi. Não vou entrar em detalhes sobre salvamento do projeto, configurações adicionais, etc. Comece o projeto adicionando 02 buttons na parte superior e um ListBox, mais ou menos como o layout abaixo. Eu gosto de usar 600px de altura e 400 de largura pra ter uma ideia do agrupamento de controles no mobile. Fique a vontade pra mudar se preferir.
A ideia é simples. No OnCreate vamos listar todos os arquivos presentes no Project > Deployment apontados para a pasta .\assets\internal\, por isso adicione alguns arquivos ao Deployment, lembrando que precisa enviar para as respectivas plataformas, Android 32 e 64, ou somente na plataforma que fará os testes.
Nesse layout teremos um botão para compactar os arquivos e outro para apagar o arquivo zipado, só para testes. No ListBox listaremos todos os arquivos na pasta. Uma ressalva, quando trabalhamos com leitura e gravação de arquivos/pastas no Android precisamos de permissão de arquivo. As permissões são:
- Read External Storage
- Write External Storage.
Use o método que desejar para pedir permissão ao sistema operacional. Eu recomendo que utilize nosso componente MobilePemissions que está disponível gratuitamente através do Tool > Get It Package Manager ou no meu GitHub.
Get It Package Manager
Git Hub Adriano Santos Treina
Caso opte por usar nosso componente, basta instalar no Delphi, atualizar o campo Search Path do projeto apontando para a pasta onde o componente foi instalado. Arraste um componente pra tela e no evento OnCreate faça:
1 2 3 4 5 |
MobilePermissions1.Dangerous.ReadExternalStorage := true; MobilePermissions1.Dangerous.WriteExternalStorage := true; MobilePermissions1.Apply; |
Em seguida vamos iniciar a codificação dos demais métodos que vamos usar no nosso tutorial. Crie uma procedure com a seguinte assinatura e em seguida pressione Ctrl + Shift + C para criar o escopo.
1 2 3 |
procedure ListarArquivosNoListBox(const pasta: string; listBox: TListBox); |
Essa procedure será usada para listarmos os arquivos da pasta .\assets\internal\ e listamos dentro do ListBox apenas com a intenção de ver quais arquivos estão na pasta. Nesse método recebemos o endereço da pasta e qual ListBox receberá a lista de arquivos. Vamos ao código da procedures:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[...] uses System.IOUtils; [...] procedure TForm1.ListarArquivosNoListBox(const pasta: string; listBox: TListBox); var arquivos: TStringDynArray; arquivo: string; begin listBox.Clear; // Limpa o ListBox antes de adicionar novos itens arquivos := TDirectory.GetFiles(pasta); for arquivo in arquivos do listBox.Items.Add(arquivo); end; |
Analisando o código, é relativamentes simples. Limpamos o ListBox e chamamos o método GetFiles passando pra ele a pasta onde os arquivos deverão ser listados e jogamos em uma variável do tipo TStringDynArray. Em seguida em um Loop For adicionamos os nomes de arquivso ao ListBox, bem molezinha né? Não esqueça de declarar a uses System.IOUtils;
Recomendo voltar ao evento OnCreate do Form e adicionar a chamada ao método, assim já abrimos o aplicativo com os arquivos listados, uma excelente ideia.
Retorne agora ao topo da unit e adicione um novo método, que será o método de compactação dos arquivos. Nesse caso não vamos usar TZilFile, usaremos outros duas classes pra isso. Vamos lá. A assinatura do método é a seguinte
1 2 3 4 |
procedure CompactarArquivos(const arquivoCompactado: string; const arquivos: TArray<string>); |
O método possui os parâmetros arquivoCompactado que recebe o nome do arquivo que será criado na compactação. E um array de arquivos que serão acrescentados no arquivo compactado final. Pressione Ctrl + Shift + C pra criar o escopo e vamos ao código do método.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
procedure TForm1.CompactarArquivos(const arquivoCompactado: string; const arquivos: TArray<string>); var zipStream: TFileStream; compressorStream: TCompressionStream; arquivo: string; begin try zipStream := TFileStream.Create(arquivoCompactado, fmCreate); try compressorStream := TCompressionStream.Create(clMax, zipStream); try for arquivo in arquivos do begin compressorStream.CopyFrom(TFileStream.Create(arquivo, fmOpenRead), 0); compressorStream.Seek(0, soFromEnd); // Move o ponteiro para o final end; finally compressorStream.Free; end; ShowMessage('Compactação concluída com sucesso!'); finally zipStream.Free; end; except on E: Exception do ShowMessage('Erro ao compactar arquivos: ' + E.Message); end; end; |
Nós vamos usar aqui as classes TFileStream e TCompressionStream pra juntar os arquivos e compactar. Iniciamos instanciando a classe TFileStream passando para ele o nome (na verdade nome e caminho) do arquivo zip que será gerado e o parâmetro fmCreate pra criar o arquivo em memória.
Em seguida instanciamos a classe TCompressionStream informando o tipo de compactação. Note que o primeiro parâmetro informamos o nível de compactação como clMax e no segundo parâmetros informamos onde será a saída dessa compactação, nesse caso no TFileStream.
Na unit System.ZLib (precisa declarar inclusive no uses) você encontra os Levels de compactação:
1 2 3 |
TCompressionLevel = (clNone = Integer(zcNone), clFastest, clDefault, clMax); |
Se preferir uma explicação mais detalhada, veja isso:
TFileStream
é uma classe que fornece acesso a arquivos em nível de byte. Ela permite a leitura e gravação sequencial de dados em um arquivo.- A principal utilização é para operações de I/O (entrada e saída) de baixo nível em arquivos. Você pode usá-la para abrir, ler, gravar e fechar arquivos.
TCompressionStream
faz parte da unidadeSystem.ZLib
e é usado para comprimir dados durante a gravação em um fluxo de saída.- Ele envolve outro stream de saída (como
TFileStream
) e comprime os dados conforme eles são gravados no stream de saída. - Essa classe é útil para compactar arquivos ou dados antes de gravá-los em disco ou transmiti-los pela rede.
Muito legal né? Retornando, depois de instanciar as devidas variáveis, iniciamos o processo de compactação em um loop, isso porque receberemos um array de arquivos para serem zipados.
Chamamos o loop como abaixo e vamos adicionando arquivo por arquivo usando o comando CopyFrom do TCompressionStream.
1 2 3 4 5 6 7 |
for arquivo in arquivos do begin compressorStream.CopyFrom(TFileStream.Create(arquivo, fmOpenRead), 0); compressorStream.Seek(0, soFromEnd); // Move o ponteiro para o final end; |
Liberamos as variáveis de memória e exibimos uma mensagem de sucesso. Fácil.
Conheça nossos treinamentos, possuímos diversos cursos de desenvolvimento Android com Delphi e também de construção de APIs REST. Clique no banner abaixo:
Agora basta fazer as chamadas. No botão Compactar (Button1 se não deu nome a ele), insira a seguinte codificação no evento OnClick ou OnTap.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
procedure TForm1.Button1Click(Sender: TObject); var arquivos: TArray<string>; begin SetLength(arquivos, 3); arquivos[0] := TPath.Combine(TPath.GetDocumentsPath, 'arquivo1.txt'); arquivos[1] := TPath.Combine(TPath.GetDocumentsPath, 'teste2.jpg'); arquivos[2] := TPath.Combine(TPath.GetDocumentsPath, 'matteo1.jpeg'); if FileExists(TPath.Combine(TPath.GetDocumentsPath, 'arquivo.zip')) then DeleteFile(TPath.Combine(TPath.GetDocumentsPath, 'arquivo.zip')); CompactarArquivos(TPath.Combine(TPath.GetDocumentsPath, 'arquivo.zip'), arquivos); ListarArquivosNoListBox(TPath.Combine(TPath.GetDocumentsPath), ListBox1); end; |
Novamente iniciamos criando uma variável para armzenar a lista de arquivos a serem compactados. Atualizamos o Lenght dessa variável em 3, o número de arquivos que coloquei nesse exemplo. Adicionamos então quais os arquivos que serão compactados alimentando o array.
Fiz um pequeno teste. Se o arquivo.zip há existir na pasta, deleto esse arquivo para que possamos chamar uma nova compactação. Por fim chamamos CompactarArquivos passando pra ele o nome do arquivo final zipado e a lista de arquivos a serem compactados.
Depois que o método termina a compactação atualizamos o ListBox chamando o método de atualização dele. Bem mole fazer a chamada não?
Aqui deixamos fixo o número de arquivos, mas é claro que você poderá elaborar melhor a ideia e fazer algo mais dinâmico.
O código do botão para apagar o arquivo zipado você já sacou né? Só replicar a chamada ao método FileExistis e chamar novamente a atualização do ListBox.
Pra você não esquecer, declare as uses System.IOUtils e System.ZLib que possuem as declarações das classes que usamos.
Conclusão
Como pudemos ver é simples demais fazer a compactação de arquivos usando as classes TFileStream e TCompresssionStream em uma aplicação Android com Firemonkey. Apesar de termos explanado o uso com Android, esse mesmo código pode ser usado também em aplicação Windows sem contra indicações. No máximo terá apenas que adaptar as chamadas das classe TFile e TDirectory para ajustar o caminho certo dos arquivos.
Espero que tenha gostado. Comente abaixo o que achou e se foi útil pra você.
E se gostou COMPARTILHE esse artivo.
Comunidade no Telegram
🚀Comente no campo abaixo 👇👇👇 o que achou e qual sua dúvida.
Te vejo na próxima.
Adriano Santos