quarta-feira, fevereiro 02, 2005

PowerBuilder – Armazenando fotos em um Banco de Dados

Cada vez está sendo mais comum desenvolvermos aplicações que utilizem fotos / imagens. Abaixo está um exemplo de como Armazenar e recuperar fotos no banco de dados.
Este exemplo foi feito utilizando Orace 8.1.7 e PowerBuilder 9.2 (Build 7554)

PASSO 1 – Crie uma tabela
Crie uma tabela com um campo próprio para armazenar este tipo de arquivo (geramente chamado como campo BLOB), que pode variar de acordo com o SGBD ( SQL Server/Sybase/ASE = Image ou Text; Oracle = Long ou Long Raw ou Blob ou CLOB)
No meu exemplo, criei a seguinte tabela no Oracle:

CREATE TABLE TESTE_FOTO
( CODIGO NUMBER(2) NOT NULL,
DESCRICAO VARCHAR2(100) NULL,
EXTENSAO VARCHAR2(4) NULL,
FOTO LONG RAW NULL,
CONSTRAINT PK_TESTE_FOTO PRIMARY KEY (CODIGO))

O campo EXTENSAO foi feito para resolver um problema existente na API do Oracle 8, quando recuperamos a foto para exibição.
É recomendado que você nunca crie o campo BLOB em uma tabela a parte, pois geralmente este campo ocupa muito espaço, tornando a tabela pesada para utilizar em consultas que recuperam múltiplos registros.
Um detalhe muito interessante é que o campo de FOTO tem que ser Nulo. O que vai ser explicado no passo 2.

PASSO 2 – Criar a DataWindow de Manutenção
Crie uma DataWindow atualizável com todos os campos da tabela, exceto o campo BLOB, pois ele será tratado a parte. Por isso o campo BLOB deve ser nulo, pois a inserção de registro na tabela e feita em dois passos:
1 – Inserção dos campos normais
2 – Atualização do valor do campo BLOB

PASSO 3 – Selecionando o arquivo a ser armazenado
Insira um Picture Control na sua Datawindow, que será utilizado para exibir a imagem e crie um código que permita selecionar a imagem, como no exemplo abaixo :

string docpath, docname
integer li_rtn

//Exibe janela para selecionar o arquivo
li_rtn = GetFileOpenName("Selecione a Imagem",docpath, docname, "JPEG",+ "JPEG (*.jpg),*.jpg," &
+ "BMP (*.BMP),*.BMP,All Files (*.*), *.*", "C:\", 18)

IF li_rtn < filename=" docpath" ls_picturename =" trim(DW_1.Object.P_1.Filename)" ll_aux =" len(ls_picturename)" ll_i =" ll_aux" ll_i =" 0"> 0 then
ls_extensao = mid(ls_picturename,ll_i + 1)
else
setNUll(ls_extensao)
end if

dw_1.setitem(1,"extensao",ls_extensao)

//Salva a DataWindow
dw_1.update()

//Transforma o arquivo em um valor Blob
WF_grava_arquivo( DW_1.Object.P_1.Filename, LL_BLOB)


lblb_imagem = LL_BLOB
ll_codigo = dw_1.getitemnumber(1,"codigo")

//Atualiza o valor blog no Banco de Dados
updateblob teste_foto
set foto = :lblb_imagem
where codigo = :ll_codigo;


//Finaliza a transacao
commit;


Código da função WF_GRAVA_ARQUIVO
wf_grava_arquivo (string as_arquivo, ref blob lblob_final);//verifica se o arquivo já existe, se existir, realiza o updade, caso contrario, realizar o insert
long ll_row, ll_codigo, ll_file, ll_tam
blob lblob_arquivo

//ll_codigo = long (sle_1.text)

//Carrega o arquivo
ll_file = FileOpen ( as_arquivo , StreamMode! , Read! , LockRead!)
if ll_file = -1 then
messagebox("Erro","Ocorreu um erro na abertura do arquivo",stopsign!)
return
end if

lBlob_final = blob('')
ll_tam = fileread(ll_file, lblob_arquivo)


do while (ll_tam > 0)
lBlob_final = lBlob_final + lblob_arquivo
ll_tam = fileread(ll_file, lblob_arquivo)
loop

fileclose(ll_file)


PASSO 5 – Neste passo iremos recuperar o arquivo do banco de dados e exibi-lo na DataWindow.
No SQL Server e Sybase, basta incluir um controle “Large binary/text Database Ole Object” e prencher as informações corretas (Na dúvida, consulte o Help do PowerBuilder).
Mas, a solução acima não funciona no Oracle, pois existem alguns problemas com este controle, onde os dados não são recuperados.
Para resolver este problema, eu tive que criar a seguinte solução
1 – Recupero o campo BLOB para uma variável BLOB
2 – Limpo os arquivos temporários existentes. Para isso, armazeno os nomes dos arquivos temporários gerados em um XML
3 – Crio o arquivo temporário a partir da variável BLOB. Por este motivo, eu armazeno a extensão do arquivo na hora de gravar, evitando conflitos de tipos de arquivos. Neste ponto, também armazeno o nome do mesmo no XML, para limpeza no futuro.
4 – Utilizando um Picture Control na DataWindow, exibo o arquivo temporário armazenado.

Abaixo está o código utilizado para fazer este procedimento :

long ll_rowcount
long ll_codigo, ll_file, ll_row
blob lblb_imagem, lBlob_final, lblob_arquivo
string ls_imagem, ls_path
datastore vld_datastore

//Configura DataStore de Gerenciamento de arquivos temporários
vld_datastore = create datastore
vld_datastore.dataobject = 'd_arquivos_temporarios'

ll_codigo = long(sle_1.text)

//Recupera os Registros
ll_rowcount = dw_1.retrieve (ll_codigo)

//Se existir registro, vai para o tratamento do Blob
if ll_rowcount > 0 then
//Seleciona o campo Blob
selectblob foto
into :lblb_imagem
from teste_foto
where codigo = :ll_codigo;

//Importa os dados do arquivo XML de controle de arquivos temporarios
vld_datastore.importfile(XML!,'C:\tmpfoto.xml')

//Apaga todos os arquivos temporarios existentes na máquina
for ll_row = vld_datastore.rowcount() to 1 step -1
filedelete(vld_datastore.getitemstring(ll_row,"filename"))
vld_datastore.deleterow(ll_row)
next

//gera um arquivo temporario, com a extensao original
ls_path = "c:\tmpfoto" + string(today(),"yyyymmdd")+string(now(),"hhmmssffff")+"."+dw_1.getitemstring(1,"extensao")

//Grava o nome do aquivo temporario no XML de controle
ll_row = vld_datastore.insertrow(0)
vld_datastore.setitem(ll_row,"filename",ls_path)
vld_datastore.saveas( "C:\tmpfoto.xml", XML!,true )


//Carrega o arquivo
ll_file = FileOpen ( ls_path , StreamMode! , write! , Lockwrite!, Replace!)
if ll_file = -1 then
messagebox("Erro","Ocorreu um erro na abertura do arquivo",stopsign!)
return
end if

//Lê o blob e grava um arquivo
lBlob_final = lblb_imagem

do while (len(lBlob_final) > 0)
lblob_arquivo = blobmid(lBlob_final,1,32000)
filewrite(ll_file,lblob_arquivo)
lBlob_final = blobmid(lBlob_final,32001)
loop

fileclose(ll_file)

//Exibe o arquivo temporario
DW_1.Object.P_1.Filename=ls_path


messagebox("Sucesso","Arquivo recuperad com sucesso!")
end if



Boa sorte!!!!

4 comentários:

Erikson Flávio disse...

Thiago, muito bom o post. Parabéns pela disseminação do conhecimento especialmente em uma linguagem com imensa dificuldade de material na net.

Almeida disse...

Thiago, excelente o Post, porem sou nova no PB e já me passaram uma super tarefa de mexer com BLOB.
Fiquei com dúvida quanto ao código:IF li_rtn < filename=" docpath" ls_picturename =" trim(DW_1.Object.P_1.Filename)" ll_aux =" len(ls_picturename)" ll_i =" ll_aux" ll_i =" 0"> 0 then
ls_extensao = mid(ls_picturename,ll_i + 1) else
setNUll(ls_extensao)
end if

Está correto?

Att.,
Almeida

José Guilherme Boaventura disse...

Thiago bom dia!
Estou tentando criar uma aplicação em PB 7.0 para mostrar fotos de produtos.
Segui seu tutorial de armazenar a foto no banco de dados.
Não ocorre nenhum erro, os dados são gravados no banco usando o comando UpdateBlog.
Até aí tudo ok.

O problema está em mostrar a foto gravada no banco de dados numa datawindow. Não aparece a foto ao utilizar o OLE Object long binary. Aparece em branco, como se o conteúdo fosse vazio.
Os dados estão gravados no banco mas não aparece a imagem.
Estou gravando/lendo uma imagem bmp.

As propriedades do Ole Object aparentemente estão certas, segundo o help.
Estou utilizando uma datawindow tabular, para mostrar vários registros.

O que poderia ser?

Obrigado e até mais.

José Guilherme



José Guilherme Boaventura disse...

Thiago bom dia!
Estou tentando criar uma aplicação em PB 7.0 para mostrar fotos de produtos.
Banco de dados Sybase.
Segui seu tutorial de armazenar a foto no banco de dados.
Não ocorre nenhum erro, os dados são gravados no banco usando o comando UpdateBlog.
Até aí tudo ok.

O problema está em mostrar a foto gravada no banco de dados numa datawindow. Não aparece a foto ao utilizar o OLE Object long binary. Aparece em branco, como se o conteúdo fosse vazio.
Os dados estão gravados no banco mas não aparece a imagem.
Estou gravando/lendo uma imagem bmp.

As propriedades do Ole Object aparentemente estão certas, segundo o help.
Estou utilizando uma datawindow tabular, para mostrar vários registros.

O que poderia ser?

Obrigado e até mais.

José Guilherme