Manual de VFP y MysQL III – Campos BLOB
INTRODUCCIÓN Sigo igual que en las anteriores, no se me ocurre nada. HERRAMIENTAS UTILIZADAS: A excepción del VFP, el software utilizado se puede encontrar en www.mysql.org • • • •
VFP 7.0 MySQL 4.0.17 MySQL Connector / ODBC 3.51 MDAC 2.1 o posterior (normalmente instalado junto con Windows)
REQUISITOS PREVIOS • •
Haber creado la base de datos y las tablas de los artículos anteriores Tener conocimientos de OLEDB
EMPEZAMOS Hemos estado utilizando la tecnología “SQL-PassThrough” durante las entregas anteriores pero, para el manejo de campos Binary Large OBjects (BLOB) utilizaremos OLEDB. CONECTÁNDONOS CON MySQL UTILIZANDO OLEDB Cadena de conexión: por no ser el tema de éste artículo sólo explicaré los parámetros necesario en ella: Ejemplo de cadena de conexión (todo en una sola línea) DRIVER={MySQL ODBC 3.51 Driver};SERVER=localhost; DATABASE=vfp_db; UID=root; PWD='
Parámetro DRIVER SERVER DATABASE UID PWD
Descripción Es el nombre del driver utilizado para realizar la conexión Nombre del servidor o IP Base de datos a la que nos queremos conectar Nombre de usuario Password del usuario
Denny Infante Juárez
[email protected]
Manual de VFP y MysQL III – Campos BLOB Probando la conexión… LOCAL ADOCnx, lRet, oRs, CnxStr ADOCnx = CREATEOBJECT('ADODB.Connection') ADOCnx.CursorLocation = 3 &&adUseClient CnxStr = 'DRIVER={MySQL ODBC 3.51 Driver};SERVER=localhost;' +; 'DATABASE=vfp_db;UID=root; PWD=' lRet = ADOCnx.Open(CnxStr, "", "") IF ADOCnx.State = 1 THEN oRs = ADOCnx.Execute('SELECT * FROM InnoClientes') IF TYPE('oRs') = 'O' THEN IF oRs.RecordCount > 0 THEN oRs.MoveFirst DO WHILE NOT oRs.Eof ?oRs.Fields[1].Value oRs.MoveNext ENDDO ELSE ?'No se obtuvieron registros de la consulta' ENDIF ELSE ?'Error en la consulta' ENDIF ADOCnx.Close() ELSE ?'ERROR: No se logró conectar con la base de datos' ENDIF
CREANDO LA TABLA PARA ALMACENAR ARCHIVOS Hasta aquí se supone que ya logramos conectarnos con MySQL ahora crearemos la tabla con un campo BLOB (ver manual de MySQL para mayor información); la estructura de la tabla es: Campo IDBlob Imagen
Tipo Campo entero autonumérico MEDIUMBLOB
Porque MEDIUMBLOB, por el tamaño de almacenamiento 16777215 bytes (ver manual de MySQL para ver capacidad de otros tipos de campos BLOB) La cadena que utilizaremos para la creación de la tabla en la base de datos: CREATE TABLE IF NOT EXISTS BlobTable PRIMARY KEY, Imagen MEDIUMBLOB)
Denny Infante Juárez
[email protected]
(IDBlob
INT
NOT
NULL
AUTO_INCREMENT
Manual de VFP y MysQL III – Campos BLOB Creando la tabla con un campo BLOB LOCAL lcError lcError = .F. ON ERROR lcError = .T. *!* Conectándonos con la base de datos LOCAL ADOCnx, lRet, oRs, CnxStr ADOCnx = CREATEOBJECT('ADODB.Connection') ADOCnx.CursorLocation = 3 &&adUseClient CnxStr = 'DRIVER={MySQL ODBC 3.51 Driver};SERVER=localhost;' +; 'DATABASE=vfp_db;UID=root; PWD=' lRet = ADOCnx.Open(CnxStr, "", "") *!* Si no nos logramos conectar IF ADOCnx.State <> 1 OR lcError THEN ?'ERROR: No se logró la conexión con la base de datos' ON ERROR ADOCnx.Close() RETURN .F. ENDIF *!* Sentencia para crear la tabla LOCAL lcSQLCreateTable lcSQLCreateTable = 'CREATE TABLE IF NOT EXISTS BlobTable ' +; '(IDBlob INT NOT NULL AUTO_INCREMENT PRIMARY KEY, ' +; 'Imagen MEDIUMBLOB)' *!* *!* *!*
Nota: con esta sentencia no esperamos que nos regrese ningún recordset así que asumiremos que si no ocurre un error la tabla ha sido creada correctamente
oRs = ADOCnx.Execute(lcSQLCreateTable) IF lcError THEN ?'ERROR: no se logró crear la tabla: ' + MESSAGE() ELSE ?'Tabla BlobTable creada!!' ENDIF ON ERROR ADOCnx.Close()
Denny Infante Juárez
[email protected]
Manual de VFP y MysQL III – Campos BLOB AGREGANDO INFORMACIÓN A LOS CAMPOS TIPO BLOB Para el manejo de campos tipo blob existen dos funciones AppendChunk y GetChunk ambas funciones pertenecen al objeto Recordset (para mayor información consultar la ayuda) Agregando el archivo a la tabla (AppendChunk) Hay dos formas de obtener la información del archivo, la primera utilizando FILETOSTR(‘Nombre del Archivo’) y la segunda utilizando FREAD(hFile, ‘Nombre del Archivo’); cual utilizar; si se van por el lado más fácil (usar FILETOSTR) tomando como referencia un archivo de 42kb este ocupará más espacio en la tabla; el tamaño de la tabla con un registro utilizando FILETOSTR es de 166 kb a diferencia de utilizar FREAD que es de 83 kb (la mitad de FILETOSTR) LOCAL lcError lcError = .F. ON ERROR lcError = .T. *!* Conectándonos con la base de datos LOCAL ADOCnx, lRet, oRs, CnxStr ADOCnx = CREATEOBJECT('ADODB.Connection') ADOCnx.CursorLocation = 3 &&adUseClient CnxStr = 'DRIVER={MySQL ODBC 3.51 Driver};SERVER=localhost;' +; 'DATABASE=vfp_db;UID=root; PWD=' lRet = ADOCnx.Open(CnxStr, "", "") *!* Si no nos logramos conectar IF ADOCnx.State <> 1 OR lcError THEN ?'ERROR: No se logró la conexión con la base de datos' ON ERROR ADOCnx.Close() RETURN .F. ENDIF *!* Cargamos el archivo que queremos guardar en la base de datos LOCAL lcImage *!* lcImage = FILETOSTR(GETFILE()) *!* ***************************************************************** *!* Del ejemplo de la ayuda de VFP *!* ***************************************************************** Local gnFileHandle,nSize,cString gnFileHandle = FOPEN("MDLogo.jpg") * Seek to end of file to determine the number of bytes in the file
Denny Infante Juárez
[email protected]
Manual de VFP y MysQL III – Campos BLOB nSize = FSEEK(gnFileHandle, 0, 2) && Move pointer to EOF IF nSize <= 0 * If the file is empty, display an error message WAIT WINDOW "This file is empty!" NOWAIT ELSE * If file is not empty, the program stores its contents * in memory, then displays the text on the main Visual FoxPro window = FSEEK(gnFileHandle, 0, 0) && Move pointer to BOF lcImage = FREAD(gnFileHandle, nSize) * ? cString ENDIF = FCLOSE(gnFileHandle) && Close the file *!* ***************************************************************** *!* Creamos y abrimos un recordset, de preferencia sin registros; esto *!* se logra con la condición WHERE oRs = CREATEOBJECT('ADODB.Recordset') oRs.Open("SELECT * FROM BlobTable WHERE 1 = 0", ADOCnx, 3, 3) *!* Agregamos un registro en blanco oRs.AddNew() *!* Cargamos los datos del archivo en el campo deseado (del tipo blob) *!* que de acuerdo con la estructura de la tabla es el segundo campo *!* pero como el arreglo de los campos está en base 0 entonces.. oRs.Fields(1).AppendChunk(lcImage) *!* Actualizamos la tabla y cerramos el recordset oRs.update() oRs.Close() IF lcError THEN ?'ERROR: no se logró agregar el archivo a la tabla ' ELSE ?'Archivo agregado!!' ENDIF ON ERROR ADOCnx.Close()
Importante: el parámetro de la función AppendChunk es el contenido del archivo, cuando
el archivo es muy largo se puede mandar en “pedacitos”; esto lo pueden logra con un ciclo; eso se los dejo a uds. Obteniendo el archivo de la tabla (GetChunk) LOCAL lcError lcError = .F. ON ERROR lcError = .T. *!* Conectándonos con la base de datos LOCAL ADOCnx, lRet, oRs, CnxStr ADOCnx = CREATEOBJECT('ADODB.Connection')
Denny Infante Juárez
[email protected]
Manual de VFP y MysQL III – Campos BLOB ADOCnx.CursorLocation = 3 &&adUseClient CnxStr = 'DRIVER={MySQL ODBC 3.51 Driver};SERVER=localhost;' +; 'DATABASE=vfp_db;UID=root; PWD=' lRet = ADOCnx.Open(CnxStr, "", "") *!* Si no nos logramos conectar IF ADOCnx.State <> 1 OR lcError THEN ?'ERROR: No se logró la conexión con la base de datos' ON ERROR ADOCnx.Close() RETURN .F. ENDIF *!* Inicializamos las variables LOCAL lcImage lcImage = '' oRs = ADOCnx.Execute('SELECT * FROM BlobTable') IF TYPE('oRs') = 'O' THEN IF oRs.RecordCount > 0 THEN LOCAL lcChunkSize, lcChunkBuffer, lcImg lcChunkSize = oRs.Fields(1).ActualSize lcChunkBuffer = 0 lcImg = '' *!* Este ciclo nos ayuda a traer por partes el archivo y no en un *!* solo “paso”; esto es más adecuado cuando el archivo es grande, *!* permite poner un indicador que muestre el porcentaje de avance, *!* y con el DOEVENTS ejecutar otras tareas mientras termina de *!* *!* descargarse el campo Do While lcChunkBuffer < lcChunkSize lcImg = oRs.Fields(1).GetChunk(100) lcImage = lcImage + lcImg lcChunkBuffer= lcChunkBuffer + 100 ENDDO *!* La siguiente línea es necesaria para convertir el texto, que nos *!* lo regresa en formato UNICODE, al formato que necesitamos para *!* grabar el archivo lcImage = STRCONV(lcImage, 6) *!* Darle el nombre con el que queremos guardar el archivo *!* con todo y extensión LOCAL hFile hFile = FCREATE('MDLogo_from_MySQL.jpg') =FWRITE(hFile, lcImage) =FCLOSE(hFile) *!* STRTOFILE(lcImage, GETFILE()) ELSE
ELSE
?'No se obtuvieron registros de la base de datos' ENDIF oRs.Close() ?'ERROR: No se logró crear el objeto Recordset'
ENDIF
Denny Infante Juárez
[email protected]
Manual de VFP y MysQL III – Campos BLOB
IF lcError THEN ?'ERROR: no se logró obtener el archivo a la tabla ' ELSE ?'Archivo grabado!!' ENDIF ON ERROR ADOCnx.Close()
COMENTARIOS ADICIONALES Recuerden que no se recomienda almacenar archivos en las tablas; lo que se recomienda es tener en la tabla la referencia al archivo, se que existen casos en el que es necesario tenerlos en la tabla para esas situaciones es que elaboré el artículo. Espero que les sea de utilidad Denny Infante Juárez
Denny Infante Juárez
[email protected]