Como transferir arquivos entre aplicações Cliente/Servidor com DataSnap

Veja neste artigo como transferir arquivos entre aplicações Cliente/Servidor usando DataSnap. Este artigo mostrará passo a passo todo o processo e o conceito envolvido nessa transferência.

Introdução

É comum em aplicações corporativas a utilização de conceitos como o GED (Gerenciamento Eletrônico de Documento) ou EDM (Enterprise Document Management) como também é conhecido, e com isso surge a necessidade de trafegar não mais só dados simples e um pouco complexos, como strings e classes, como também dados muito mais complexos, como documentos.

Como foi dito anteriormente GED é o acrônimo de Gerenciamento Eletrônico de Documento, que é na verdade é um conjunto de tecnologias ou filosofias, como alguns preferem se referir, que visa solucionar problemas com o processo atual de forma inteligente, segura e funcional.

O intuito deste artigo não é desenvolver uma aplicação utilizando filosofias e/ou conceitos de GED, mas sim mostrar o processo de transferência desses documentos para assim poderem utilizar o GED. Para este processo vamos serializar ou encapsular o documento em JSON para que assim possamos facilmente trafegar esses documentos entre aplicações Cliente/Servidor sem perder a capacidade do servidor atuar em meios híbridos, ou seja, ser consumido por outras linguagens.

Prática

Crie um servidor DataSnap, adicione um server module ao projeto e declare o método da Listagem 1, que vai ser o responsável por receber o arquivo JSON, mas a sua implementação acontecerá mais a frente.

Listagem 1: Declaração do método do servidor responsável por receber o objeto JSON

procedure pUploadArquivo(pArquivoJSON : TJSONArray);

Vamos adicionar uma aplicação cliente e fazer as devidas configurações para que a aplicação Cliente se comunique com a aplicação servidora e logo após gere a classe proxy. Crie uma tela parecida com a da Figura 1.

Figura 1: Tela da aplicação cliente

Agora vamos criar um método na aplicação cliente que fará o processo de serialização do arquivo para JSON, veja na Listagem 2 a sua declaração. Antes de implementar este método é necessário declarar a unit Data.DBXJSON para quem possui a versão do Delphi XE2 ou XE3 e para as demais basta incluir a unit DBXJSON.

Listagem 2: Declaração do método na aplicação cliente responsável por serializar o arquivo em JSON

function fArquivoParaJSON(pDirArquivo : string) : TJSONArray;

Agora vamos para a implementação da função acima que receberá como parâmetro o caminho do arquivo e retorna com o arquivo serializado, confira na Listagem 3 a implementação.

Listagem 3: Implementação do método fArquivoParaJSON descrito na Listegem2


var
  sBytesArquivo, sNomeArquivo: string;
  oSSArquivoStream: TStringStream;
  iTamanhoArquivo, iCont: Integer;
begin
  try
    Result := TJSONArray.Create; // Instanciando o objeto JSON que conterá o arquivo serializado

    oSSArquivoStream := TStringStream.Create; // Instanciando o objeto stream que carregará o arquivo para memoria
    oSSArquivoStream.LoadFromFile(pDirArquivo);  // Carregando o arquivo para memoria
    iTamanhoArquivo := oSSArquivoStream.Size; // pegando o tamanho do arquivo

    sBytesArquivo := '';

    // Fazendo um lanço no arquivo que está na memoria para pegar os bytes do mesmo
    for iCont := 0 to iTamanhoArquivo - 1 do
    begin
      // A medida que está fazendo o laço para pegar os bytes, os mesmos são jogados para
      // uma variável do tipo string separado por ","
      sBytesArquivo := sBytesArquivo + IntToStr(oSSArquivoStream.Bytes[iCont]) + ', ';
    end;

    // Como é colocado uma vírgula após o byte, fica sempre sobrando uma vígugula, que é deletada
    Delete(sBytesArquivo, Length(sBytesArquivo)-1, 2);

    // Adiciona a string que contém os bytes para o array JSON
    Result.Add(sBytesArquivo);

    // Adiciona para o array JSON o tamanho do arquivo
    Result.AddElement(TJSONNumber.Create(iTamanhoArquivo));

    // Extrai o nome do arquivo
	  sNomeArquivo := ExtractFileName(pDirArquivo);

    // Adiciona na terceira posição do array JSON o nome do arquivo
    Result.AddElement(TJSONString.Create(sNomeArquivo));
  finally
    oSSArquivoStream.Free;
  end;
end;

Agora vamos implementar o botão do form principal que enviará o objeto para o servidor. Confira sua implementação na Listagem 4.

Listagem 4: Implementação do evento click do botão Enviar Arquivo mostrado na Figura


procedure TFViewPrincipal.BEnviarArquivoClick(Sender: TObject);
var oArquivoJSON : TJSONArray;
    oProxy : TSMArquivoClient;
begin
  //Converte o arquivo passado por parâmetro em JSON
  oArquivoJSON := fArquivoParaJSON('C:\Users\Public\Pictures\Sample Pictures\Lighthouse.jpg');
  MJSON.Text := oArquivoJSON.ToString; // Joga o valor JSON no memo

  // Instância a classe proxy
  SQLCServidor.Connected := True;
  oProxy := TSMArquivoClient.Create(SQLCServidor.DBXConnection);
  try
    // Envia o arquivo em JOSN para o servidor
    oProxy.pUploadArquivo(oArquivoJSON);
  finally
    oProxy.Free; // Libera o objeto proxy da memoria
  end;
end;

Agora que a aplicação cliente foi devidamente programada, vamos voltar para a aplicação servidora e criar um novo método chamado pJSONParaArquivo como mostra a Listagem 5, que será o responsável por deserializar o objeto JSON e transformá-lo em arquivo.

Listagem 5: Declaração do método pJSONParaArquivo no servidor


TSMArquivo = class(TDSServerModule)
  private
    procedure pJSONParaArquivo(pArquivoJSON : TJSONArray; const pDir : string);
  public
    procedure pUploadArquivo(pArquivoJSON : TJSONArray);
  end;

Agora vamos implementar o método pJSONParaArquivo como mostra a Listagem 6.

Listagem 6: Implementação do método pJSONParaArquivo


procedure TSMArquivo.pJSONParaArquivo(pArquivoJSON: TJSONArray;
  const pDir: string);
var
  SSArquivoStream: TStringStream;
  sArquivoString, sNomeArquivo: String;
  iTamanhoArquivo, iCont: Integer;
  SLArrayStringsArquivo: TStringList;
  byArquivoBytes: Tbytes;
begin
  try
    sArquivoString := pArquivoJSON.Get(0).ToString;  // Pega a posição 0 do array que contem os bytes do arquivo
    Delete(sArquivoString, Length(sArquivoString), 1); // Deleta a última aspas da string
    Delete(sArquivoString, 1, 1); // Deleta a primeira aspas da string

    sNomeArquivo := pArquivoJSON.Get(2).ToString;  // Pega o nome do arquivo que está na posição 2
    Delete(sNomeArquivo, Length(sNomeArquivo), 1); // Deleta a última aspas da string
    Delete(sNomeArquivo, 1, 1); // Deleta a primeira aspas da string

    iTamanhoArquivo := TJSONNumber(pArquivoJSON.Get(1)).AsInt; // Pega na posição 1 o tamanho do arquivo

    SLArrayStringsArquivo := TStringList.Create; // Cria um obje do tipo TStringList para emparelhar os bytes
    ExtractStrings([','], [' '], PChar(sArquivoString), SLArrayStringsArquivo); // Coloca cada byte em uma linha no objeto TStringList

    SetLength(byArquivoBytes, iTamanhoArquivo); // Seta o tamanho do array de bytes igual ao tamanho do arquivo

    // Faz um laço para pegar os bytes do objeto TStringList
    for iCont := 0 to iTamanhoArquivo - 1 do
    begin
      //Pega os bytes do TStringList e adiciona no array de bytes
      byArquivoBytes[iCont] := StrToInt(SLArrayStringsArquivo[iCont]);
    end;
    SSArquivoStream := TStringStream.Create(byArquivoBytes); // Instancia o objeto TStringStream para salvar o arquivo

    // Verifica se o diretório passado por parâmetro não existe
    if not DirectoryExists(pDir) then
      ForceDirectories(pDir); // Se não existir o diretório vai ser criado

    SSArquivoStream.SaveToFile(pDir + sNomeArquivo); // Salvar o arquivo no hd
  finally
    SSArquivoStream.Free;
    SLArrayStringsArquivo.Free;
  end;
end;

Por fim vamos implementar o método pUploadArquivo, que vai ser chamado pelo cliente. Confira sua implementação na Listagem 7.

Listagem 7: Implementação do método pUploadArquivo


procedure TSMArquivo.pUploadArquivo(pArquivoJSON: TJSONArray);
begin
  pJSONParaArquivo(pArquivoJSON, 'C:\Users\WelsonPlay\Desktop\'); // Deserialização do array JSON para arquivo
end;

Pronto. Terminamos também o servidor e agora já podemos testar.

Conclusão

Como foi visto nesse artigo, é bem simples realizar a transferência de arquivo entre aplicações Cliente/Servidor e com esses conceitos que foram adquiridos nesse artigo já podemos ter uma base para o desenvolvimento de aplicações corporativas com um grau ainda maior de complexidade.

É importante ressaltar que utilizando estas técnicas de serialização em JSON, os nossos servidores já ficam aptos para serem consumidas por aplicações feitas em outras linguagens como C#, Java, PHP e etc., desde que as mesmas suportem JSON, que praticamente todas suportam.

Este post está bem simples e bem objetivo, não está se pegando em como criar um servidor DataSnap ou uma aplicação cliente, pois não é o foco desse artigo, e sim está focando no real objetivo desse artigo que é a transferência de arquivos entre aplicações.

Outro ponto que se deve ressaltar é que esse processo de serialização pode demorar um pouco de acordo com o tamanho do arquivo, então o ideal é esse processo ser feito dentro de uma thread e também exibir informações sobre o progresso para que o usuário possa acompanhar o envio de forma visual, mas como esse também não é o foco desse artigo não foi frisado e nem explicado.

Ficamos por aqui, e fiquem livres para escrever comentários, críticas e sugestões para novos artigos. Fiquem com Deus.


Sugestões de leitura

Artigos relacionados