News & Events
Tutorial: Download e Upload de arquivos binários em Base64 com Mobile e DataSnap 2/2
- 30 de setembro de 2016
- Posted by: Adriano Santos
- Category: Notícias
Em nosso último post entitulado Tutorial: Download e Upload de arquivos binários em Base64 com Mobile e DataSnap 1/2 nós vimos como fazer download de fotos de um servidor DataSnap para a aplicação cliente, mobile nesse caso. Apredemos a criar um método no servidor capaz de baixar o arquivo para a aplicação cliente usando TStream, assim o arquivo é baixado em pacotes. Nós também apredemos que o método criado por nós pode ser usado para qualquer tipo de arquivo. Em nosso exemplo, fizemos uso de arquivos com a extesão .JPG, ou seja, arquivos de imagem. Nessa segunda parte, vamos fazer o inverso, ou seja, tirar uma foto nova no mobile e envia-la para ser gravada em uma pasta no servidor.
Download e Upload de arquivos binários em Base64
Em nossa jornada, vamos começar novamente pelo servidor. Vou mostrar a vocês como criar um método capaz de receber o arquivo que será enviado pela a aplicação cliente. Abra então o projeto servidor DataSnap e logo em seguida em acesse a unit do seu ServerMethods. Acesse a seção Public e declare um novo método, como abaixo:
function UploadFile(const AFile: String; const ASetStream: TStream): Boolean;
Deixe-me explicar o que estamos fazendo. O parâmetro AFile é o nome do arquivo que será enviado do mobile para o server. Por fim, adicionei um parâmetro ASetStream, o mais importante. Esse parâmetro é responsável por receber o “pacote” em memória do referente ao arquivo de imagem. Dentro do servidor receberemos esse arquivo por pacotes e então salvaremos na pasta “img”. Ótimo então. Vamos agora codificar o método. Pressione Ctrl + Shift + C para criar o escopo e cole o código abaixo no novo método.
function TMetodosGerais.UploadFile(const AFile: String; const ASetStream: TStream): Boolean; var FileStream : TStream; Mem : TMemoryStream; Buffer : PByte; BufSize : Integer; BytesRead : Integer; Target : String; begin Result := True; BufSize := 1024; try Mem := TMemoryStream.Create; GetMem(Buffer, BufSize); try FileStream := ASetStream; FileStream.Position := 0; repeat BytesRead := FileStream.Read(Pointer(Buffer)^, BufSize); if (BytesRead > 0) then Mem.WriteBuffer(Pointer(Buffer)^, BytesRead); until (BytesRead < BufSize); Target := ExtractFilePath('..\..\..\img\') + AFile; Mem.SaveToFile(Target); Result := True; finally FreeMem(Buffer, BufSize); FreeAndNIl(Mem); end; except on E: Exception do Result := False; end; end;
Novamente, o código é um pouco longo, mas não se assuste. É fácil entender. Na primeira etapa do código, nós estamos declarando as variáveis para controle de memória e recebimento do arquivo. Não explicarei todas, vamos as principais. A variável FileStream será responsável por receber o arquivo enviado no parâmetro ASetStream e então lido até remontar o arquivo do lado server. Poderíamos usar diretamente o parâmetro. Deixei assim apenas para tentar facilitar a didática. Loco em seguida, mais ao final da seção var, declaramos Target. Essa variável é usada para capturarmos o caminho onde o arquivo será salvo, como fizemos na aplicação cliente.
Em seguida vamos analisar o código do método em si. Perceba que inicializamos a variável FileStream atribuindo a ela o valor do parâmetro ASetStream. Em seguida iniciamos o loop repeat…until para fazer a leitura dos bytes do arquivo.
repeat BytesRead := FileStream.Read(Pointer(Buffer)^, BufSize); if (BytesRead > 0) then Mem.WriteBuffer(Pointer(Buffer)^, BytesRead); until (BytesRead < BufSize);
Do mesmo modo que fizemos na aplicação cliente, estamos fazendo na server. Aqui nós lemos o conteúdo da variável FileStream, que contém o arquivo carregado em memória, e escrevemos seu conteúdo na variável Mem, de memória. Ao terminar o loop, resgatamos o caminho onde o arquivo será salvo concatenando-o ao nome dele recebido em AFile. Por fim, usamos o método SaveToFile da variável Mem para salva-lo propriamente dito. O resto é tratamento de erro. Fácil né? Então vamos até o código da aplicação mobile.
Target := ExtractFilePath('..\..\..\img\') + AFile; Mem.SaveToFile(Target);
Envio da imagem pelo app mobile
Nós vamos fazer aqui dois procedimentos. O primeiro deles é criar o método para ativar a câmera do celular, tirar a foto e então usa-la. Para isso, insira no form principal um componente TActionList. Clique duas vezes sobre ele e então na janela que se abre clique na pequena seta preta ao lado direito do botão New Action. Escolha New Standard Action e na janela aberta, escolha TTakePhotoFromCameraAction.
Agora selecione o item criado, acesse o Object Inspector e na aba Events. Dê dois cliques no evento OnDidFinishTaking para codificarmos esse evento. Apenas digite o código abaixo. Na sequência, vincule a propriedade Action do botão Carregar Foto, inserido na parte 1 desse tutorial, à nossa nova Action. Isso fará com que ao tocar no botão, a câmera seja acionada e após confirmar a nova foto o componente Image1 seja atualizado.
Image1.Bitmap.Assign(Image);
Estamos quase terminando. Agora faremos o código do botão Upload. Por isso, acesse seu evento OnClick e digite o código a seguir.
procedure TfrmPrincipal.Button2Click(Sender: TObject); var ImgTarget: String; FileStr : String; fStream : TStream; Size : Int64; begin try FileStr := 'ImagemCapturada.jpg'; ImgTarget := System.IOUtils.TPath.Combine( System.IOUtils.TPath.GetDocumentsPath, FileStr); if TFile.Exists(ImgTarget) then TFile.Delete(ImgTarget); Image1.Bitmap.SaveToFile(ImgTarget); fStream := TFileStream.Create(ImgTarget, fmOpenRead or fmShareDenyNone); Size := fStream.Size; fStream.Position := 0; if CM.MetodosGeraisClient.UploadFile(FileStr, Size, fStream) then ShowMessage('Arquivo Enviado') else ShowMessage('Ocorreu algum erro, refaça a operação'); finally FStream.Free; end; end;
Vejamos o que todo esse código faz. Primeiro declaramos as variáveis necessárias para nossa brincadeira, começando por ImgTarget. Para que possamos enviar o arquivo ao servidor, precisamos não somente tirar a foto, mas também salva-la na pasta Documents do smartphone para que se tranforme em um arquivo físico. Essa variável fará o trabalho de capturar o diretório e nome do arquivo que desejamos salvar. Em seguida invocamos o método Exists da classe TFile para verificarmos se o arquivo já existe na pasta, isso porque criamos um novo fixo chamado ‘ImagemCaputurada.jpg’. Se o arquivo existir, excluímos. Em seguida usamos o método SaveToFile da propriedade Bitmap do componente Image1. Salvamos na pasta passando a variável ImgTarget.
O próximo passo é instanciar a variável FStream do tipo TStream que transportará o arquivo para a memória. Capturamos o seu tamanho, que nesse exemplo não estamos usando para nada, apenas como didáticas para sabermos como capturar essa informação. Poderá ser usado no futuro por você, caso deseje atualizar uma ProgressBar como fizemos no donwload. Por fim, a parte mais importante. Chamamos o método UploadFile do servidor usando a linha abaixo:
if CM.MetodosGeraisClient.UploadFile(ImgTarget, Size, fStream) then ShowMessage('Arquivo Enviado') else ShowMessage('Ocorreu algum erro, refaça a operação');
Perceba que fazemos um IF chamando a função, isso porque criamos um método do tipo Boolean para verificar se o envio foi concluído ou não. O restante da função é a liberação de memória da variável FStream. Note também que no primeiro parâmetro estamos enviando a variável FileStr que não comentei, mas possui apenas o nome do arquivo separado (‘ImagemCapturada.jpg’). Você pode criar seu próprimo mecanismo para dar nomes aos arquivos. Por fim passamos o a variável FStream que será recebida pelo servidor. O resto, você já sabe o que ocorrerá.
Compile seu projeto e teste. A nova foto tirada será enviada ao servidor DataSnap e salva no diretório ‘img’ com o nome ‘ImagemCapturada.jpg’.
Conclusão
Como pudemos ver nesses dois passos de nosso tutorial, não há nada de extraordinário no envio e recebimento de arquivos (nesse caso imagens) para um servidor DataSnap. O legal de tudo isso é que podemos fazer esse mesmo mecanismo para qualquer outro tipo de arquivo. Um exemplo disso? Podemos por exemplo criar um método no servidor que gere um relatório em PDF e esse arquivo pode ser baixado para o smartphone ou tablet, enfim, há inúmeras aplicabilidades para isso. Espero que tenha gostado.
Obrigado, bons estudos e até a próxima.
#GoToDelphi