Gravando e resgatando PDF de banco Access com Blob

Delphi

22/11/2013

Olá pessoal, este é o meu primeiro post aqui no DEVMEDIA!

Estou com um problema em um projeto onde há a necessidade de gravar um arquivo PDF no banco de dados, pois solicitaram que ele não fique exposto em uma pasta. O banco é Access XP ainda, pois é a única versão que posso usar aqui por ser um órgão público e ter somente ele disponível.

No banco o campo que recebe o documento PDF é do tipo OLE, sendo que ao gravar o dado, consigo ver na tabela que algo está naquele campo, o Access mostra somente a inscrição 'binários longos' . Estou tentando resolver o problema usando BLOB, que funcionou fácil na gravação, porém na recuperação / amostragem não.

Outro item que tenho grande dúvida é quanto o uso do comando ShellExecute, sei que seu funcionamento é fácil, até fiz uns testes aqui, porém não consigo mostrar ao Delphi como carregar aquele registro no banco e mostrá-lo em PDF.

Vale ressaltar que a conexão com o banco de dados funciona normalmente (ADOConnection, ADOQuery e DataSource).

Bom... abaixo segue o código de um exemplo de aplicação voltada somente para resolver este problema. Quem tiver alguma noção, por favor, me ajude!

unit unit_blob;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, ADODB, StdCtrls, ExtCtrls, ShellApi, DBCtrls, OleCtnrs, DBClient, dbtables;

type
  TForm1 = class(TForm)
    SaveDialog1: TSaveDialog;
    btAnexar: TButton;
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    btInserir: TButton;
    Shape1: TShape;
    btVisualizar: TButton;
    cdsTemporario: TClientDataSet;
    cdsTemporarioarquivoPDF: TBlobField;
    Memo1: TMemo;
    procedure btAnexarClick(Sender: TObject);
    procedure btInserirClick(Sender: TObject);
    procedure btVisualizarClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


// Anexando dados (funcional) ++++++++++++++++++++++++++++++++++++++++++++++++++
procedure TForm1.btAnexarClick(Sender: TObject);
begin
  SaveDialog1.Execute;

  if (SaveDialog1.FileName <> '') then
    begin
      Memo1.Lines.SaveToFile(SaveDialog1.FileName);
      Memo1.Text := SaveDialog1.FileName;
        //Propriedade text usada pelo fato do nome do arquivo não aparecer
        //no memo automaticamente.
    end;
end;

// Inserido dados (funcional) ++++++++++++++++++++++++++++++++++++++++++++++++++
procedure TForm1.btInserirClick(Sender: TObject);
begin
    ADOQuery1.Close; //Fecha conexões antigas...
    ADOQuery1.SQL.Clear; //Limpa conexões...
    ADOQuery1.SQL.Add('insert into tbl_arquivo (arquivo) values (:param_cx_arquivo)'); //Faz a inserção...
    ADOQuery1.Parameters.ParamByName('param_cx_arquivo').LoadFromFile(memo1.Text, ftBlob); //Dado recebido...
      //Load carrega o dado para o banco, vai em formato blob...
   try
    ADOQuery1.ExecSQL; //Execução da Query.
    ShowMessage('Registro gravado com sucesso!');
   except
    ShowMessage('Erro ao gravar dados...');
   end;

end;

// Visualizando / Recuperando dados (não funcional) ++++++++++++++++++++++++++++
procedure TForm1.btVisualizarClick(Sender: TObject);
  var
    blob : TBlobField;
    software : String;
    caminho : String;
    dado : String;
begin
    //Consultando
    ADOQuery1.Close; //Fecha conexões antigas...
    ADOQuery1.SQL.Clear; //Limpa conexões...
    ADOQuery1.SQL.Add('select arquivo from tbl_arquivo where codigo = 3'); //Faz a inserção...
    ADOQuery1.Open; //Execução da Query.

    {
      Daqui em diante não sei como proceder...
      A consulta é bastante simples, pois ela será implementada após resolver
      sobre o resgate / apresentação dos dados.
    }
end;
end.
Diego Bispo

Diego Bispo

Curtidas 0

Melhor post

Diego Bispo

Diego Bispo

09/12/2013

Olá! Eu de novo... pessoal, fui tentando e tentando, recebi ajuda de colegas de trabalho e cheguei a uma resolução, que na verdade era bastante simples. Creio até que o meu problema fosse outro e não sabia, pois pelo que vi, o resgate e apresentação dos dados funcionou bem, porém o problema estava na gravação, onde enviava para o banco um dado qualquer, e não o conteúdo do arquivo. Vejam a seguir a solução, que foi testada no Access 2000 e no MySQL, claro que para cada um havia uma conexão configurada corretamente, além disso o código de teste de conexão MySQL só funciona no respectivo banco.

Dica: o TMemoryStream é um grande aliado, fique de olho nele!

Minha solução:

unit unit_blob;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, ADODB, StdCtrls, ExtCtrls, ShellApi, DBCtrls, OleCtnrs, DBClient, DBTables;

type
  TForm1 = class(TForm)
    SaveDialog1: TSaveDialog;
    btAnexar: TButton;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    btInserir: TButton;
    Shape1: TShape;
    btVisualizar: TButton;
    Memo1: TMemo;
    lblResultado: TLabel;
    ADOConnection1: TADOConnection;
    procedure btAnexarClick(Sender: TObject);
    procedure btInserirClick(Sender: TObject);
    procedure btVisualizarClick(Sender: TObject);
    procedure btTestaConexaoClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


// Anexando dados (funcional) ++++++++++++++++++++++++++++++++++++++++++++++++++
procedure TForm1.btAnexarClick(Sender: TObject);
  var
    arquivo : TMemoryStream;

begin
  SaveDialog1.Execute;

  if (SaveDialog1.FileName <> '') then
    begin
      //Carregamento da imagem:
      arquivo := TMemoryStream.Create;

      //Alocando o conteúdo da SaveDialog na variável.
      Memo1.Lines.SaveToStream(arquivo);

      //Mostrando o nome ao usuário.
      Memo1.Text := SaveDialog1.FileName;
          //Propriedade text usada pelo fato do nome do arquivo não aparecer
          //no memo automaticamente.
    end;
end;

// Inserido dados (não funcional) ++++++++++++++++++++++++++++++++++++++++++++++++++
procedure TForm1.btInserirClick(Sender: TObject);
begin
    //Gravando os dados...
    ADOQuery1.Close; //Fecha conexões antigas...
    ADOQuery1.SQL.Clear; //Limpa conexões...
    ADOQuery1.SQL.Add('insert into tbl_arquivo (arquivo) values (:param_cx_arquivo)'); //Faz a inserção...
    ADOQuery1.Parameters.ParamByName('param_cx_arquivo').LoadFromFile(Memo1.Lines.Text, ftBlob); //Dado recebido...

   //Executa a query.
   try
    ADOQuery1.ExecSQL; //Execução da Query.

    ShowMessage('Registro gravado com sucesso!');
   except
    ShowMessage('Erro ao gravar dados...');
   end;

end;

// Visualizando / Recuperando dados (funcional) ++++++++++++++++++++++++++++
procedure TForm1.btVisualizarClick(Sender: TObject);
  var
    //Tratando Blob
    S : TMemoryStream;
    FileStream : TFileStream;

    //Confirmação de informações
    resultado : Integer;

begin
    //Consultando
    ADOQuery1.Close; //Fecha conexões antigas...
    ADOQuery1.SQL.Clear; //Limpa conexões...
    ADOQuery1.SQL.Add('select arquivo from tbl_arquivo where codigo = 23'); //Faz a inserção...
    ADOQuery1.Open; //Execução da Query.

    //Contando o resultado...
    resultado := ADOQuery1.RecordCount;
    lblResultado.Caption := 'Resultado da pesquisa: '+ IntToStr(resultado) +' registro(s) encontrado(s).';
    lblResultado.Visible := True;


     S := TMemoryStream.Create;
      try
        //Criação do arquivo que receberá o pdf...
        FileStream := TFileStream.Create('c:\arquivo.pdf', fmCreate);

        //Salvamento do conteúdo do arquivo dentro da memória Ram...
        TBlobField(ADOQuery1.FieldByName('arquivo')).SaveToStream(S);

        //Ainda não sei a função do posicionamento...
        S.Position := 0;

        //Transferência dos dados da Ram para o arquivo criado
        FileStream.CopyFrom(S, S.Size);

        //Abertura do arquivo.
        //RESULT := 'c:\arquivo.pdf';
        ShellExecute(handle, 'open', 'c:\arquivo.pdf', '', '', SW_SHOWNORMAL);

      finally
        S.Free;
        FileStream.Free;
      end;

end;

//Testando a conexão com o banco MySQL... (funcional)
procedure TForm1.btTestaConexaoClick(Sender: TObject);
begin
  try
    ADOConnection1.Open();
    ShowMessage('Conectou!!');
  except
    on erro_ao_conectar: Exception do
      ShowMessage(erro_ao_conectar.Message);
  end;
end;

end.
GOSTEI 1

Mais Respostas

Diego Bispo

Diego Bispo

22/11/2013

Pessoal, na verdade o Access que estou usando é o 2000... mais velho do que pensei!
GOSTEI 0
Douglas

Douglas

22/11/2013

Cara, pergunta, oq seria o ":param_cx_arquivo" que você tem ali na inserção ?
GOSTEI 0
Emerson Nascimento

Emerson Nascimento

22/11/2013

no lugar disto:
     S := TMemoryStream.Create;
      try
        //Criação do arquivo que receberá o pdf...
        FileStream := TFileStream.Create('c:\\arquivo.pdf', fmCreate);
 
        //Salvamento do conteúdo do arquivo dentro da memória Ram...
        TBlobField(ADOQuery1.FieldByName('arquivo')).SaveToStream(S);
 
        //Ainda não sei a função do posicionamento...
        S.Position := 0;
 
        //Transferência dos dados da Ram para o arquivo criado
        FileStream.CopyFrom(S, S.Size);
 
        //Abertura do arquivo.
        //RESULT := 'c:\\arquivo.pdf';
        ShellExecute(handle, 'open', 'c:\\arquivo.pdf', '', '', SW_SHOWNORMAL);
 
      finally
        S.Free;
        FileStream.Free;
      end;
 


não poderia ser somente isto:
      try
        TBlobField(ADOQuery1.FieldByName('arquivo')).SaveToFile('c:\\arquivo.pdf');
        ShellExecute(handle, 'open', 'c:\\arquivo.pdf', '', '', SW_SHOWNORMAL);
       except
      end;
GOSTEI 0
Emerson Nascimento

Emerson Nascimento

22/11/2013

Respondi e nem vi que o post era beeeem antigo....
GOSTEI 0
POSTAR