Page 1 of 1

Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Mon Mar 09, 2015 1:23 am
by jnavas
// Almacena archivos de cualquier tipo en una tabla DBF o Gestor MySQL/SQLSERVER
// Juan navas jnavas@datapronet.com jnadaptapro@gmail.com
// Este programa fue extraido del sistema ERP AdaptaPro www.datapronet.com utiliza MYSQL
// Este ejemplo es mi aporte al foro de FiveWin, se puede utilizar en cualquier gestor de base de datos utilizando campos Memos
// El mecanismo es: A partir del Archivo BMP o Binario, Genera un archivo comprimido ZIP,texto mediante MIME, se fracciona en paginas y se almacena
// Para recuperarlo: Lee el contenido del memo, genera el archivo TEXTO, luego genera el archivo comprimido, finalmente se descomprime y genera el archivo nuevamente en la carpeta filerecover
// Requiere Libreria hbzlib.LIB
// Ejecucion desde la consola: savefilebmp <Nombre de Cualquier Archivo>
// Si no se indica el nombre del archivo, guardara el mismo binario y luego lo recupera en la carpeta filerecover
// Esta funcionalidad la hemos ìmplementado con campos BLOB y LONGTEXT en MYSQL.

#include "FiveWin.ch"

FUNCTION MAIN(cFile)
LOCAL aPag
LOCAL cBin :=Lower(GetModuleFileName( GetInstance() ))
LOCAL cFileDir:="FILES.DBF"
LOCAL cFilePag:="FILESPAG.DBF"
LOCAL aFile,I

DEFAULT cFile:=cBin

SET DELETE ON

IF !FILE(cFile)
MsgAlert("Archivo "+cFile+" no Existe")
RETURN NIL
ENDIF

ISTABLAS(cFileDir,cFilePag)

aFile:=DIRECTORY(cFile)
aPag :=GETPAGES(cFile)

IF Empty(aPag)
MsgAlert("Archivo no generó Paginado")
RETURN NIL
ENDIF

SELECT A
USE (cFileDir) EXCLU
GO TOP
// Remueve el COntenido
DELETE ALL FOR ALLTRIM(FIELD->FILE)=ALLTRIM(cFile)
PACK

APPEND BLANK
REPLACE FILE WITH cFile
REPLACE SIZE WITH aFile[1,2]
REPLACE PAGES WITH LEN(aPag)
COMMIT

// BROWSE()

SELECT B
USE (cFilePag) EXCLU
GO TOP
// Remueve el COntenido
DELETE ALL FOR ALLTRIM(FIELD->FILE)=ALLTRIM(cFile)
PACK

FOR I=1 TO LEN(aPag)
APPEND BLANK
REPLACE FILE WITH cFile
REPLACE PAGE WITH I
REPLACE MEMO WITH aPag
COMMIT
NEXT I

// BROWSE()

CLOSE ALL

RECUPERAR(cFile)

RETURN NIL

FUNCTION cFileTemp(cExt)
LOCAL cFile:="tmp"+STRTRAN(LSTR(SECONDS()),".","")+cExt
RETURN cFile

FUNCTION lstr(nValue)
RETURN ALLTRIM(STR(nValue))


FUNCTION GETPAGES(cFileOrg)
LOCAL cFileZip :=cFileTemp(".ZIP")
LOCAL cFileMime:=cFileTemp(".TXT")
LOCAL aFiles :={},nSize:=0,oFile,cMemo:=""
LOCAL cBin :=Lower(cFilePath(GetModuleFileName( GetInstance() )))
LOCAL aPages:={},I,aTotal:={},nTotal:=0,lZip:=.F.
LOCAL aPag :={},nPage
LOCAL nFileMax :=(1024**4)*2 // Tamaño maximo permitido para almacenar, en paginado el limite esta en la capacidad de la tabla
LOCAL nPageSize:=(1024**2)/2 // Tamaño maximo de la Pagina, limite campo MEMO . Utilizado en MySQL para campos LONGTEXT

nPageSize:=65555 // Capacidad para tablas DBF

CursorWait()

IF !(":"$cFileOrg)
cFileOrg:=cBin+cFileOrg
ENDIF

cFileOrg :=Lower(cFileOrg)

AADD(aFiles,cFileOrg)

IF !(":"$cFileOrg)

MsgAlert("Es necesario Indicar la Ruta Completa del Archivo "+cFileOrg+CRLF+;
"Ejemplo "+cBin+"\docs\documento.doc")

RETURN 0

ENDIF

IF !FILE(cFileOrg)
MsgAlert("Archivo "+cFileOrg+" no Existe")
RETURN 0
ENDIF

IF UPPE(cFileExt(cFileOrg))="ZIP"
cFileZip:=cFileOrg
lZip :=.T.
ELSE
// El Archivo Original es Comprimido en Formato Zip
HB_ZipFile( cFileZip, aFiles, 9,,.T., NIL, .F., .F. )
ENDIF

// El Archivo MIME es Convertido en Formato TEXTO Segun Mime
FMimeEnc(cFileZip,cFileMime)

// Valida el Tamaño con el Archivo MIME
nSize:=DIRECTORY(cFileMime)[1,2]

IF nSize>nFileMax
MsgAlert("Archivo "+cFileMime+" Tamaño "+LSTR(nSize)+",Supera el Límite "+LSTR(nFileMax))
RETURN {}
ENDIF

// Determinamos las Páginas que seran empleadas

nPage :=MAX(INT(nSize/nPageSize),1)
aPages:={}

FOR I=1 TO nPage
AADD(aPages,{MIN(nPageSize,nSize)})
NEXT I

aTotal:=ATOTALES(aPages)

// Remanente de la Ultima Página
IF nSize>aTotal[1]
AADD(aPages,{nSize-aTotal[1]})
ENDIF

// Se Extra Pagina por Pagina del Arhivo MIME
oFile:=TFILE():New(cFileMime)

FOR I=1 TO LEN(aPages)
cMemo:=oFile:cGetStr( aPages[I,1] )
AADD(aPag,cMemo)
nTotal:=nTotal+LEN(cMemo)
NEXT I

oFile:End()

ferase(cFileMime)

IF !lZip
ferase(cFileZip)
ENDIF

RETURN aPag

FUNCTION ATOTALES(aData)
LOCAL aTotal,I,U

aTotal:=ARRAY(LEN(aData[1]))

Aeval( aTotal,{ |a,n| aTotal[n]:=0 })

FOR I=1 TO LEN(aData)

FOR U=1 TO LEN(aData)
aTotal:=aTotal+aData[I,U]
NEXT U

NEXT I

RETURN aTotal

PROCE ISTABLAS(cFileDir,cFilePag)
LOCAL aStruct:={}

IF FILE(cFileDir)
RETURN
ENDIF

AADD(aStruct,{"FILE", "C",250,0})
AADD(aStruct,{"SIZE", "N",12 ,0})
AADD(aStruct,{"PAGES","N",3 ,0})

dbcreate(cFileDir, aStruct)

aStruct:={}
AADD(aStruct,{"FILE","C",250,0}) // Archivo
AADD(aStruct,{"PAGE","N",4 ,0}) // Memo
AADD(aStruct,{"MEMO","M",0 ,0}) // Numero de la Pagina, es necesario el Orden para su Recuperación

dbcreate(cFilePag, aStruct)

RETURN

FUNCTION RECUPERAR(cFile)
LOCAL cFileDir:="FILES.DBF"
LOCAL cFilePag:="FILESPAG.DBF"
LOCAL cFileZip :=cFileTemp(".ZIP")
LOCAL cFileMime:=cFileTemp(".TXT")
LOCAL I,cDirOut:="filerecover\"

LOCAL aPag :={}
LOCAL oFile

lMkDir(cDirOut)

SELECT A
USE (cFileDir)
GO TOP
LOCATE FOR ALLTRIM(FIELD->FILE)=ALLTRIM(cFile)

IF !FOUND()
CLOSE ALL
MsgAlert("Archivo "+cFile+" no Encontrado en Tabla "+cFileDir)
RETURN .F.
ENDIF

SELECT B
USE (cFilePag) EXCLU
GO TOP
// Remueve el COntenido
LOCATE FOR ALLTRIM(FIELD->FILE)=ALLTRIM(cFile)

WHILE !EOF() .AND. ALLTRIM(FIELD->FILE)=ALLTRIM(cFile)
AADD(aPag,ALLTRIM(FIELD->MEMO))
SKIP
ENDDO

CLOSE ALL

// Desde DBF hacia MIME

oFile:=TFILE():New(cFileMime)
AEVAL(aPag,{|a,n| oFile:PutStr(a)})
oFile:End()

// De MIME a ZIP
ferase(cFileZip)
FMimeDec(cFileMime,cFileZip)
ferase(cFileMime)

HB_UNZIPFILE( cFileZip , {|| nil }, .t., NIL, cDirOut , NIL )
ferase(cFileZip)

MsgAlert("Archivo recuperado en carpeta "+cDirOut)

IF !cFileExt(cFile)="EXE"
SHELLEXECUTE(NIL,"open",cFile)
ENDIF

RETURN .T.

Re: Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Mon Mar 09, 2015 4:51 am
by Antonio Linares
Juan,

gracias por compartirlo :-)

Re: Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Mon Mar 09, 2015 5:26 am
by jnavas
Antonio,
Muchas gracias espero que sea de utilidad, al principio tuve muchas dificultades para implementar en mi aplicacion el registro y recuperación de todo tipo de archivo.

Re: Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Mon Mar 06, 2017 4:07 am
by Andrés González
Juan, Sencillamente una genialidad, es posible ponerse en contacto contigo. Tu correo no funciona.

Re: Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Mon Mar 06, 2017 11:22 am
by nageswaragunupudi
Probably this very difficult approach was necessary during 16-bit clipper days about 20 years back.
Now all this totally not necessary.
We can simply assign file buffer value to the field.

Please try this sample which stores contents of a large file c:\fwh\lib\fiveh32.lib in the memo field of dbf file.

Code: Select all

#include "fivewin.ch"

REQUEST DBFCDX

function Main()

   local cFile    := "c:\fwh\lib\fiveh32.lib" // file size is 5,480,0032

   DBCREATE( "contents.dbf", { { "FILENAME", 'C', 128, 0 }, { "CONTENTS", 'M', 8, 0 } }, "DBFCDX" )
   USE contents EXCLUSIVE

   DBAPPEND()
   FIELD->FILENAME   := cFile
   FIELD->CONTENTS   := MEMOREAD( cFile )

   DBCOMMIT()

   ? LEN( field->contents ), FILESIZE( cfile ) // --> 5480032, 5480032

   CLOSE CONTENTS

return nil
 
Same way even for storing large BLOB or TEXT data in MySql, MsSql or other databases, it can be done in one simple step.

MYSQL Example (using FWHMYSQL and can be tested with FWH 17.01):
Principle is the same for other libraries too.

Code: Select all

#include "fivewin.ch"

function Main()

   // MYSQL
   local oCn, oRs
   local cFile    := "c:\fwh\lib\fiveh32.lib"

   oCn   := FW_DemoDB( 1 )
   // Note: It is important to set max_allowed_packet to sufficiently large value eg. 32MB

   if oCn:TableExists( "contents" )
      oCn:DropTable( "contents" )
   endif
   oCn:CreateTable( "contents", { { "filename", 'C', 128, 0 }, { "contents", 'm', 8, 0 } } )
   oCn:Insert( "contents", "filename,contents", { cFile, MEMOREAD( cFile ) } )

   oRs   := oCn:RowSet( "contents" )
   ? Len( oRs:contents ), FILESIZE( cfile ) // --> 5480032, 5480032

   oCn:Close()

return nil

Re: Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Mon Aug 27, 2018 8:27 pm
by jnavas
Andrés González wrote:Juan, Sencillamente una genialidad, es posible ponerse en contacto contigo. Tu correo no funciona.
Saludos
Puedes escribirme a jnavas@datapronet.com o adaptaprodrive@gmail.com

Re: Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Tue Aug 28, 2018 7:27 am
by ellano
Muy interesante tu método, sin embargo, te puedo decir que por mi larga experiencia manejando bases de datos con miles de imágenes y videos de todo tipo que he llegado a la conclusión de que es preferible lo siguiente:

1. Un campo para almacenar el directorio donde el usuario almacena las imágenes (puede ser absoluto o relativo, recomiendo relativo o todo se vuelve una confusión total si el programa cambia de posición o si entregas un instalable; por ejemplo, con Innosetup http://jrsoftware.org/). Tipo texto longitud 120.
2. Un campo en el que se almacena el tipo de imagen (BMP, JPG, etc) de longitud 4. Esto es optativo.
3. Un campo tipo texto en el que almacenas el nombre de las imágenes. Yo lo hago así y me da muy buen resultado: Campo tipo texto de longitud 254 en el que el nombre máximo de las imágenes de limita a 8 caracteres sin espacios ni símbolos especiales y cada imagen se separa por un delimitador (yo uso ^). Esto me da la posibilidad de almacenar 254/9 (incluye el nombre del fichero y delimitador = 28 imágenes. Puedes jugar con la longitud permitida para el nombre de la imagen y/o incluir el tipo de imagen con el nombre.

El resultado es 3 campos de texto de un máximo de 120+4+254=378, sin blobs, memos, ni extras en la base de datos.

Emiliano Llano Díaz

Re: Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Tue Aug 28, 2018 11:06 am
by jnavas
Emiliano
Saludos,

En nuestro caso, AdaptaPro es un sistema Open Source creado con HB + FW + MySQL, el proceso de actualización del sistema lo realizamos mediante el alojamiento de sus componentes en AdaptaPro Server, mas las personalizaciones creadas por los clientes. ha sido eficiente rápido y cómodo hacer las actualizaciones del sistema y distribución en los demás PC involucrados con la aplicación. Hemos erradicado la participación del personal técnico para la actualización del sistema.

Tambien para _, utilizamos funcionalidades utilizar directorios y archivos donde no es necesario que estén almacenados en la BD

Re: Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Thu Feb 11, 2021 7:12 pm
by AIDA
Hola y como sacas el archivo para leerlo por decir una fotografía para presentarla en pantalla

estoy usando dbf

Saluditos :wink:

Hello and how do you get the file to read it by saying a photograph to present it on screen

i am using dbf

Greetings: wink:

nageswaragunupudi wrote:Probably this very difficult approach was necessary during 16-bit clipper days about 20 years back.
Now all this totally not necessary.
We can simply assign file buffer value to the field.

Please try this sample which stores contents of a large file c:\fwh\lib\fiveh32.lib in the memo field of dbf file.

Code: Select all

#include "fivewin.ch"

REQUEST DBFCDX

function Main()

   local cFile    := "c:\fwh\lib\fiveh32.lib" // file size is 5,480,0032

   DBCREATE( "contents.dbf", { { "FILENAME", 'C', 128, 0 }, { "CONTENTS", 'M', 8, 0 } }, "DBFCDX" )
   USE contents EXCLUSIVE

   DBAPPEND()
   FIELD->FILENAME   := cFile
   FIELD->CONTENTS   := MEMOREAD( cFile )

   DBCOMMIT()

   ? LEN( field->contents ), FILESIZE( cfile ) // --> 5480032, 5480032

   CLOSE CONTENTS

return nil
 
Same way even for storing large BLOB or TEXT data in MySql, MsSql or other databases, it can be done in one simple step.

MYSQL Example (using FWHMYSQL and can be tested with FWH 17.01):
Principle is the same for other libraries too.

Code: Select all

#include "fivewin.ch"

function Main()

   // MYSQL
   local oCn, oRs
   local cFile    := "c:\fwh\lib\fiveh32.lib"

   oCn   := FW_DemoDB( 1 )
   // Note: It is important to set max_allowed_packet to sufficiently large value eg. 32MB

   if oCn:TableExists( "contents" )
      oCn:DropTable( "contents" )
   endif
   oCn:CreateTable( "contents", { { "filename", 'C', 128, 0 }, { "contents", 'm', 8, 0 } } )
   oCn:Insert( "contents", "filename,contents", { cFile, MEMOREAD( cFile ) } )

   oRs   := oCn:RowSet( "contents" )
   ? Len( oRs:contents ), FILESIZE( cfile ) // --> 5480032, 5480032

   oCn:Close()

return nil

Re: Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Thu Feb 11, 2021 10:28 pm
by nageswaragunupudi
Saving image to DBF

Code: Select all

ALIAS->MEMOFIELDNAME := MEMOREAD( cImageFile )
 
Display image in window / dialog:

Code: Select all

@ r, c XIMAGE oImage SOURCE ALIAS->MEMOFIELDNAME SIZE w,h OF oDlg
 

Re: Almacenar/Recuperar imagenes, binarios en Tablas DBF

Posted: Fri Feb 12, 2021 12:09 am
by AIDA
Thank you very much :mrgreen:

Regards :wink:



nageswaragunupudi wrote:Saving image to DBF

Code: Select all

ALIAS->MEMOFIELDNAME := MEMOREAD( cImageFile )
 
Display image in window / dialog:

Code: Select all

@ r, c XIMAGE oImage SOURCE ALIAS->MEMOFIELDNAME SIZE w,h OF oDlg