{"id":205,"date":"2024-02-19T20:47:31","date_gmt":"2024-02-19T23:47:31","guid":{"rendered":"https:\/\/adrianosantostreina.com.br\/blog\/?p=205"},"modified":"2024-04-06T13:38:56","modified_gmt":"2024-04-06T16:38:56","slug":"como-compactar-arquivos-no-android-com-fmx","status":"publish","type":"post","link":"https:\/\/adrianosantostreina.com.br\/blog\/como-compactar-arquivos-no-android-com-fmx\/","title":{"rendered":"Como compactar arquivos no Android com FMX?"},"content":{"rendered":"\n<p>H\u00e1 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\u00e7\u00e3o em meus treinamentos ou aplicativos que desenvolvo, apesar de acreditar ser totalmente poss\u00edvel. <\/p>\n\n\n\n<p><strong>Como compactar arquivos no Android?<\/strong><\/p>\n\n\n\n<p>No Delphi possu\u00edmos classes de compacta\u00e7\u00e3o de arquivos como a <strong>TZipFile <\/strong>o que era de se esperar. Por isso a possibilidade de fazer uso delas em FMX \u00e9 totalmente racional. Ent\u00e3o decidi montar um pequeno exemplo onde isso \u00e9 poss\u00edvel. Espero que goste do tutorial.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h4 class=\"wp-block-heading\">Construindo a aplica\u00e7\u00e3o<\/h4>\n\n\n\n<p>O primeiro passo, evidentemente, \u00e9 come\u00e7ar criar uma nova aplica\u00e7\u00e3o no Firemonkey seguindo a op\u00e7\u00e3o <em>File &gt; New &gt; Multi-Device Application Delphi<\/em>. N\u00e3o vou entrar em detalhes sobre salvamento do projeto, configura\u00e7\u00f5es adicionais, etc. Comece o projeto adicionando <em>02 buttons<\/em> na parte superior e um <em>ListBox<\/em>, 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.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img fetchpriority=\"high\" decoding=\"async\" width=\"415\" height=\"616\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/Captura-de-tela-19-02-2024-15.17.23.png\" alt=\"\" class=\"wp-image-206\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/Captura-de-tela-19-02-2024-15.17.23.png 415w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/Captura-de-tela-19-02-2024-15.17.23-202x300.png 202w\" sizes=\"(max-width: 415px) 100vw, 415px\" \/><\/figure><\/div>\n\n\n<p>A ideia \u00e9 simples. No <strong>OnCreate <\/strong>vamos listar todos os arquivos presentes no <em>Project &gt; Deployment<\/em> apontados para a pasta <strong>.\\assets\\internal\\<\/strong>, 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\u00e1 os testes.<\/p>\n\n\n\n<p>Nesse layout teremos um bot\u00e3o para compactar os arquivos e outro para apagar o arquivo zipado, s\u00f3 para testes.  No ListBox listaremos todos os arquivos na pasta. Uma ressalva, quando trabalhamos com leitura e grava\u00e7\u00e3o de arquivos\/pastas no Android precisamos de permiss\u00e3o de arquivo. As permiss\u00f5es s\u00e3o:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Read External Storage<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Write External Storage.<\/li>\n<\/ul>\n\n\n\n<p>Use o m\u00e9todo que desejar para pedir permiss\u00e3o ao sistema operacional. Eu recomendo que utilize nosso componente <strong>MobilePemissions <\/strong>que est\u00e1 dispon\u00edvel gratuitamente atrav\u00e9s do T<em>ool &gt; Get It Package Manager<\/em> ou no meu GitHub.<\/p>\n\n\n\n<p>Get It Package Manager<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" width=\"675\" height=\"176\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/image.png\" alt=\"\" class=\"wp-image-207\" style=\"width:840px;height:auto\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/image.png 675w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/image-300x78.png 300w\" sizes=\"(max-width: 675px) 100vw, 675px\" \/><\/figure><\/div>\n\n\n<p>Git Hub Adriano Santos Treina<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" width=\"1024\" height=\"571\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/image-1-1024x571.png\" alt=\"\" class=\"wp-image-208\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/image-1-1024x571.png 1024w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/image-1-300x167.png 300w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/image-1-768x428.png 768w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/image-1.png 1090w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<p><\/p>\n\n\n\n<p>Caso opte por usar nosso componente, basta instalar no Delphi, atualizar o campo <strong>Search Path<\/strong> do projeto apontando para a pasta onde o componente foi instalado. Arraste um componente pra tela e no evento OnCreate fa\u00e7a:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"theme:mm-dark-blue font:monospace lang:default decode:true \" >\nMobilePermissions1.Dangerous.ReadExternalStorage := true;\nMobilePermissions1.Dangerous.WriteExternalStorage := true;\nMobilePermissions1.Apply;\n<\/pre><\/div>\n\n\n\n<p>Em seguida vamos iniciar a codifica\u00e7\u00e3o dos demais m\u00e9todos que vamos usar no nosso tutorial. Crie uma procedure com a seguinte assinatura e em seguida pressione Ctrl + Shift + C para criar o escopo.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"theme:mm-dark-blue lang:default decode:true \" >\nprocedure ListarArquivosNoListBox(const pasta: string; listBox: TListBox);\n<\/pre><\/div>\n\n\n\n<p>Essa procedure ser\u00e1 usada para listarmos os arquivos da pasta .\\assets\\internal\\ e listamos dentro do ListBox apenas com a inten\u00e7\u00e3o de ver quais arquivos est\u00e3o na pasta. Nesse m\u00e9todo recebemos o endere\u00e7o da pasta e qual ListBox receber\u00e1 a lista de arquivos. Vamos ao c\u00f3digo da procedures:<br><\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"theme:mm-dark-blue lang:default decode:true \" >[...]\nuses\n   System.IOUtils;\n[...]\nprocedure TForm1.ListarArquivosNoListBox(const pasta: string; listBox: TListBox);\nvar\n  arquivos: TStringDynArray;\n  arquivo: string;\nbegin\n  listBox.Clear; \/\/ Limpa o ListBox antes de adicionar novos itens\n  arquivos := TDirectory.GetFiles(pasta);\n  for arquivo in arquivos do\n    listBox.Items.Add(arquivo);\nend;<\/pre><\/div>\n\n\n\n<p>Analisando o c\u00f3digo, \u00e9 relativamentes simples. Limpamos o ListBox e chamamos o m\u00e9todo GetFiles passando pra ele a pasta onde os arquivos dever\u00e3o ser listados e jogamos em uma vari\u00e1vel do tipo <strong>TStringDynArray<\/strong>. Em seguida em um Loop For adicionamos os nomes de arquivso ao ListBox, bem molezinha n\u00e9? N\u00e3o esque\u00e7a de declarar a uses <strong>System.IOUtils<\/strong>;<\/p>\n\n\n\n<p>Recomendo voltar ao evento <strong>OnCreate<\/strong> do Form e adicionar a chamada ao m\u00e9todo, assim j\u00e1 abrimos o aplicativo com os arquivos listados, uma excelente ideia.<\/p>\n\n\n\n<p>Retorne agora ao topo da unit e adicione um novo m\u00e9todo, que ser\u00e1 o m\u00e9todo de compacta\u00e7\u00e3o dos arquivos. Nesse caso n\u00e3o vamos usar TZilFile, usaremos outros duas classes pra isso. Vamos l\u00e1. A assinatura do m\u00e9todo \u00e9 a seguinte<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"theme:mm-dark-blue lang:default decode:true \" >procedure CompactarArquivos(const arquivoCompactado: string; \n  const arquivos: TArray&lt;string&gt;);<\/pre><\/div>\n\n\n\n<p>O m\u00e9todo possui os par\u00e2metros <strong>arquivoCompactado <\/strong>que recebe o nome do arquivo que ser\u00e1 criado na compacta\u00e7\u00e3o. E um <strong>array<\/strong> de arquivos que ser\u00e3o acrescentados no arquivo compactado final. Pressione Ctrl + Shift + C pra criar o escopo e vamos ao c\u00f3digo do m\u00e9todo.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"theme:mm-dark-blue lang:default decode:true \" >procedure TForm1.CompactarArquivos(const arquivoCompactado: string; const arquivos: TArray&lt;string&gt;);\nvar\n  zipStream: TFileStream;\n  compressorStream: TCompressionStream;\n  arquivo: string;\nbegin\n  try\n    zipStream := TFileStream.Create(arquivoCompactado, fmCreate);\n    try\n      compressorStream := TCompressionStream.Create(clMax, zipStream);\n      try\n        for arquivo in arquivos do\n        begin\n          compressorStream.CopyFrom(TFileStream.Create(arquivo, fmOpenRead), 0);\n          compressorStream.Seek(0, soFromEnd); \/\/ Move o ponteiro para o final\n        end;\n      finally\n        compressorStream.Free;\n      end;\n      ShowMessage('Compacta\u00e7\u00e3o conclu\u00edda com sucesso!');\n    finally\n      zipStream.Free;\n    end;\n  except\n    on E: Exception do\n      ShowMessage('Erro ao compactar arquivos: ' + E.Message);\n  end;\nend;<\/pre><\/div>\n\n\n\n<p>N\u00f3s vamos usar aqui as classes <strong>TFileStream<\/strong> e <strong>TCompressionStream<\/strong> 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\u00e1 gerado e o par\u00e2metro <strong>fmCreate<\/strong> pra criar o arquivo em mem\u00f3ria.<\/p>\n\n\n\n<p>Em seguida instanciamos a classe TCompressionStream informando o tipo de compacta\u00e7\u00e3o. Note que o primeiro par\u00e2metro informamos o n\u00edvel de compacta\u00e7\u00e3o como <strong>clMax<\/strong> e no segundo par\u00e2metros informamos onde ser\u00e1 a sa\u00edda dessa compacta\u00e7\u00e3o, nesse caso no TFileStream.<\/p>\n\n\n\n<p>Na unit System.ZLib (precisa declarar inclusive no uses) voc\u00ea encontra os Levels de compacta\u00e7\u00e3o:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"theme:mm-dark-blue lang:default decode:true \" >TCompressionLevel = (clNone = Integer(zcNone), clFastest, clDefault, clMax);<\/pre><\/div>\n\n\n\n<p>Se preferir uma explica\u00e7\u00e3o mais detalhada, veja isso:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>TFileStream<\/code> \u00e9 uma classe que fornece acesso a arquivos em n\u00edvel de byte. Ela permite a leitura e grava\u00e7\u00e3o sequencial de dados em um arquivo.<\/li>\n\n\n\n<li>A principal utiliza\u00e7\u00e3o \u00e9 para opera\u00e7\u00f5es de I\/O (entrada e sa\u00edda) de baixo n\u00edvel em arquivos. Voc\u00ea pode us\u00e1-la para abrir, ler, gravar e fechar arquivos.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>TCompressionStream<\/code> faz parte da unidade <code>System.ZLib<\/code> e \u00e9 usado para comprimir dados durante a grava\u00e7\u00e3o em um fluxo de sa\u00edda.<\/li>\n\n\n\n<li>Ele envolve outro stream de sa\u00edda (como <code>TFileStream<\/code>) e comprime os dados conforme eles s\u00e3o gravados no stream de sa\u00edda.<\/li>\n\n\n\n<li>Essa classe \u00e9 \u00fatil para compactar arquivos ou dados antes de grav\u00e1-los em disco ou transmiti-los pela rede.<\/li>\n<\/ul>\n\n\n\n<p>Muito legal n\u00e9? Retornando, depois de instanciar as devidas vari\u00e1veis, iniciamos o processo de compacta\u00e7\u00e3o em um loop, isso porque receberemos um array de arquivos para serem zipados.<\/p>\n\n\n\n<p>Chamamos o loop como abaixo e vamos adicionando arquivo por arquivo usando o comando CopyFrom do TCompressionStream.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"theme:mm-dark-blue lang:delphi decode:true \" >for arquivo in arquivos do\nbegin\n  compressorStream.CopyFrom(TFileStream.Create(arquivo, fmOpenRead), 0);\n  compressorStream.Seek(0, soFromEnd); \/\/ Move o ponteiro para o final\nend;<\/pre><\/div>\n\n\n\n<p>Liberamos as vari\u00e1veis de mem\u00f3ria e exibimos uma mensagem de sucesso. F\u00e1cil.<\/p>\n\n\n\n<p>Conhe\u00e7a nossos treinamentos, possu\u00edmos diversos cursos de desenvolvimento Android com Delphi e tamb\u00e9m de constru\u00e7\u00e3o de APIs REST. Clique no banner abaixo:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/adrianosantos.link\/treinamentos\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"150\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/Banner-Hotmart-1.png\" alt=\"\" class=\"wp-image-222\" style=\"width:842px;height:auto\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/Banner-Hotmart-1.png 800w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/Banner-Hotmart-1-300x56.png 300w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/02\/Banner-Hotmart-1-768x144.png 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/a><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Agora basta fazer as chamadas. No bot\u00e3o <strong>Compactar<\/strong> (Button1 se n\u00e3o deu nome a ele), insira a seguinte codifica\u00e7\u00e3o no evento OnClick ou OnTap.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"theme:mm-dark-blue lang:default decode:true \" >procedure TForm1.Button1Click(Sender: TObject);\nvar\n  arquivos: TArray&lt;string&gt;;\nbegin\n  SetLength(arquivos, 3);\n  arquivos[0] := TPath.Combine(TPath.GetDocumentsPath, 'arquivo1.txt');\n  arquivos[1] := TPath.Combine(TPath.GetDocumentsPath, 'teste2.jpg');\n  arquivos[2] := TPath.Combine(TPath.GetDocumentsPath, 'matteo1.jpeg');\n  if FileExists(TPath.Combine(TPath.GetDocumentsPath, 'arquivo.zip')) then\n    DeleteFile(TPath.Combine(TPath.GetDocumentsPath, 'arquivo.zip'));\n  CompactarArquivos(TPath.Combine(TPath.GetDocumentsPath, 'arquivo.zip'), arquivos);\n  ListarArquivosNoListBox(TPath.Combine(TPath.GetDocumentsPath), ListBox1);\nend;<\/pre><\/div>\n\n\n\n<p>Novamente iniciamos criando uma vari\u00e1vel para armzenar a lista de arquivos a serem compactados. Atualizamos o Lenght dessa vari\u00e1vel em 3, o n\u00famero de arquivos que coloquei nesse exemplo. Adicionamos ent\u00e3o quais os arquivos que ser\u00e3o compactados alimentando o array.<\/p>\n\n\n\n<p>Fiz um pequeno teste. Se o arquivo.zip h\u00e1 existir na pasta, deleto esse arquivo para que possamos chamar uma nova compacta\u00e7\u00e3o. Por fim chamamos <strong>CompactarArquivos<\/strong> passando pra ele o nome do arquivo final zipado e a lista de arquivos a serem compactados.<\/p>\n\n\n\n<p>Depois que o m\u00e9todo termina a compacta\u00e7\u00e3o atualizamos o ListBox chamando o m\u00e9todo de atualiza\u00e7\u00e3o dele. Bem mole fazer a chamada n\u00e3o?<\/p>\n\n\n\n<p>Aqui deixamos fixo o n\u00famero de arquivos, mas \u00e9 claro que voc\u00ea poder\u00e1 elaborar melhor a ideia e fazer algo mais din\u00e2mico.<\/p>\n\n\n\n<p>O c\u00f3digo do bot\u00e3o para apagar o arquivo zipado voc\u00ea j\u00e1 sacou n\u00e9? S\u00f3 replicar a chamada ao m\u00e9todo FileExistis e chamar novamente a atualiza\u00e7\u00e3o do ListBox.<\/p>\n\n\n\n<p>Pra voc\u00ea n\u00e3o esquecer, declare as uses System.IOUtils e System.ZLib que possuem as declara\u00e7\u00f5es das classes que usamos.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Conclus\u00e3o<\/h4>\n\n\n\n<p>Como pudemos ver \u00e9 simples demais fazer a compacta\u00e7\u00e3o de arquivos usando as classes TFileStream e TCompresssionStream em uma aplica\u00e7\u00e3o Android com Firemonkey. Apesar de termos explanado o uso com Android, esse mesmo c\u00f3digo pode ser usado tamb\u00e9m em aplica\u00e7\u00e3o Windows sem contra indica\u00e7\u00f5es. No m\u00e1ximo ter\u00e1 apenas que adaptar as chamadas das classe TFile e TDirectory para ajustar o caminho certo dos arquivos.<\/p>\n\n\n\n<p>Espero que tenha gostado. <strong>Comente abaixo o que achou e se foi \u00fatil pra voc\u00ea<\/strong>.<br>E se gostou COMPARTILHE esse artivo.<\/p>\n\n\n\n<p>Comunidade no <a href=\"https:\/\/t.me\/AdrianoSantosCommunity\">Telegram<\/a><\/p>\n\n\n\n<p>\ud83d\ude80Comente no campo abaixo \ud83d\udc47\ud83d\udc47\ud83d\udc47 o que achou e qual sua d\u00favida.<\/p>\n\n\n\n<p>Te vejo na pr\u00f3xima.<\/p>\n\n\n\n<p>Adriano Santos<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Aprenda a compactar arquivos diretamente no aplicativo Android.<\/p>\n","protected":false},"author":1,"featured_media":371,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-205","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/205","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/comments?post=205"}],"version-history":[{"count":87,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/205\/revisions"}],"predecessor-version":[{"id":446,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/205\/revisions\/446"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/media\/371"}],"wp:attachment":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/media?parent=205"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/categories?post=205"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/tags?post=205"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}