Unas preguntas que frecuentemente hacen quienes empiezan con Firebird son:

¿Conviene guardar las fotografías dentro o fuera de la Base de Datos?

En el caso de Firebird se recomienda guardarlas dentro, las ventajas son:

    • La fotografía está siempre disponible. Si se copia la Base de Datos en otra computadora las fotografías también estarán allí
    • Si se hace un backup, las fotografías también estarán en el backup
    • Si se hace un shadow, las fotografías también estarán en el shadow
    • Solamente pueden insertar fotografías los usuarios autorizados
    • Solamente pueden borrar fotografías los usuarios autorizados
    • Solamente pueden modificar fotografías los usuarios autorizados
    • Solamente puede ver fotografías los usuarios autorizados
    • El acceso a las fotografías es rapidísimo
    • No necesitas tener una carpeta compartida para que los usuarios puedan ver las fotografías

O sea que no existe la posibilidad de que tengas los datos y no las fotografías que corresponden a esos datos. Por ejemplo, si en tu tabla ALUMNOS tienes sus fotografías siempre podrás verlas, si las fotografías estuvieran afuera de la Base de Datos podrías copiarla sin copiar también la carpeta donde guardas las fotografías. O alguien podría borrar la carpeta donde guardas las fotografías. O algún gracioso modificar esas fotografías y quizás ponerles bigotes y barbas, escribir texto ofensivo, cosas así.

En cambio, si la fotografía se guarda dentro de la Base de Datos y alguien quiere realizar algún tipo de vandalismo siempre podrás saber quien fue, desde cual computadora y cuando, ya que puedes guardar los datos del usuario que manipuló cada fotografía.

Si guardas las fotografías afuera de la Base de Datos entonces necesitarás que la carpeta donde se encuentran esas fotografías sea compartida para que puedan acceder a ellas todos los usuarios. Sin embargo, tener carpetas compartidas implica un gran riesgo de seguridad porque desde muchas computadoras es posible acceder a ellas y por lo tanto no es aconsejable tenerlas. Si las fotografías (y demás contenido multimedia) se encuentran dentro de la Base de Datos entonces no necesitas usar carpetas compartidas y todo es más seguro y más confiable.

¿Cómo se guardan las fotografías dentro de la Base de Datos?

Como la gran mayoría de las fotografías tienen un tamaño mayor a 32.767 bytes no podemos utilizar el tipo de datos VARCHAR para guardarlas, ya que ése es su límite máximo. En su lugar usamos el tipo de datos BLOB, ya que éste no tiene límites. En un BLOB podemos guardar no solamente fotografías sino también música, vídeo, documentos PDF, documentos Word, planillas Excel, etc.

Cuando una columna se declara que es de tipo BLOB el Firebird guarda en esa columna un número de 8 bytes que indica en cual página de la Base de Datos se encuentra el contenido. O sea, lo que se guarda en la columna no es el contenido del BLOB sino un puntero, una referencia, al lugar dentro de la Base de Datos donde se encuentra el contenido de ese BLOB. Este concepto de puntero es muy similar al usado en los campos memo de las tablas .DBF

De esta manera, si escribes el comando SELECT * FROM ALUMNOS no se están trayendo las fotografías de todos los alumnos sino solamente las referencias a esas fotografías. Haciéndolo de esta manera el Firebird consigue que la velocidad sea rapidísima porque trae solamente 8 bytes por cada fila en lugar de, por ejemplo, los 85.000 bytes que en promedio ocupa cada fotografía.

Cuando quieres obtener una fotografía para mostrársela al usuario debes específicamente pedirle al Firebird esa fotografía.

¿Cómo se declara una columna que contendrá fotografías?

Hay dos tipos de BLOB prefijados: subtipo 0 (para archivos binarios) y subtipo 1 (para archivos de texto).

En general para fotografías se usa el subtipo 1.

NOTA PARA QUIENES USAN VISUAL FOXPRO:  El subtipo 0 pasa al Visual FoxPro como un campo General. El subtipo 1 pasa al Visual FoxPro como un campo Memo.

¿Cómo se hace para guardar fotografías en la Base de Datos y mostrarlas después?

NOTA: Esto es específico para el lenguaje Visual FoxPro, en otros lenguajes debería ser similar:

Para guardar una fotografía:

lnIdenti     = 12345                    && Identificador del alumno
lcFotografia = "C:\MISFOTOS\FOTO1.JPG"  && Fotografía del alumno
lcFotografia = FileToStr(lcFotografia)  && Fotografía convertida a texto

lcComando = "UPDATE ALUMNOS SET ALU_FOTOGR = ?lcFotografia WHERE ALU_IDENTI = ?lnIdenti"

lnResultado = SQLExec(gnHandle, lcComando)

IF lnResultado > 0
   =MESSAGEBOX("Fotografía grabada exitosamente")
ELSE
   =MESSAGEBOX("No se pudo grabar la fotografía")
ENDIF

En este ejemplo, se intentó grabar la fotografía FOTO1.JPG que corresponde al alumno cuyo Identificador es 12345. Luego, se muestra un mensaje según que la grabación haya tenido éxito o no.

Para mostrar una fotografía, forma simple:

lnIdenti = 12345
lcConsulta = "SELECT ALU_FOTOGR FROM ALUMNOS WHERE ALU_IDENTI = ?lnIdenti"

llConsultaOK = SQLExec(gnHandle, lcConsulta)

COPY MEMO ALU_FOTOGR TO CurDir() + "TEMP.JPG"

THISFORM.Image1.Picture = CurDir() + "TEMP.JPG"

Aquí, la columna ALU_FOTOGR de la tabla ALUMNOS del Firebird pasó al Visual FoxPro como un campo memo. Ese campo memo es entonces copiado al disco duro C: con un nombre de archivo (puede ser cualquier nombre) y la extensión .JPG (la extensión debe ser la misma que fue usada cuando se guardó la fotografía, el nombre del archivo puede ser cualquiera). Después, simplemente se mostró en el formulario el archivo que tiene la extensión .JPG

Para mostrar una fotografía, forma más profesional:

Aunque la forma simple puede funcionar, a veces ocurren errores (por ejemplo, el alumno aún no tiene una fotografía) que deben ser detectados antes de mostrarla.

lnIdenti = 12345
lcConsulta = "SELECT ALU_FOTOGR FROM ALUMNOS WHERE ALU_IDENTI = ?lnIdenti"

lnResultado = SQLExec(gnHandle, lcConsulta)

IF lnResultado > 0
   IF !IsNull(ALU_FOTOGR)
      CLEAR RESOURCES
      lnNumVeces = 0
      llFotografiaOK = .F.
      DO WHILE lnNumVeces <= 3 .and. !llFotografiaOK
         llFotografiaOK = .T.
         TRY
            COPY MEMO ALU_FOTOGR TO CurDir() + "TEMP.JPG"
            ThisForm.Image1.Picture = CurDir() + "TEMP.JPG"
         CATCH
            llFotografiaOK = .F.
         ENDTRY
         lnNumVeces = lnNumVeces + 1
      ENDDO
      IF !llFotografiaOK
         =MESSAGEBOX("No se pudo obtener la fotografía de este alumno")
      ENDIF
   ELSE
      =MESSAGEBOX("Este alumno aún no tiene una fotografía")
   ENDIF
ELSE
   =MESSSAGEBOX("Falló la conexión con la Base de Datos")
ENDIF

En este caso primero se verifica si se pudo obtener la columna ALU_FOTOGR ya que la conexión con la Base de Datos pudo haber fallado por algún motivo (cable roto, router descompuesto, etc.). Segundo, se verifica si el alumno tiene una fotografía. Si la columna ALU_FOTOGR es NULL entonces no tiene fotografía. Si tiene una fotografía entonces se trata de copiarla al disco duro y luego mostrarla, se realizan tres intentos porque a veces el primer intento falla, sobre todo si hay problemas en la red. Podrías aumentar la cantidad de veces en que se intenta si tu red suele tener problemas.

Para mostrar la fotografía sin previamente guardarla en el disco duro:

También tienes la posibilidad de mostrar la fotografía sin guardarla en el disco duro. O sea que en lugar de escribir:

COPY MEMO ALU_FOTOGR TO CurDir() + "TEMP.JPG"
ThisForm.Image1.Picture = CurDir() + "TEMP.JPG"

Puedes simplemente escribir:

ThisForm.Image1.PictureVal = ALU_FOTOGR

De esta forma no se guardarán en el disco duro las fotografías que los usuarios miran, algo que a veces puede ser útil y a veces no.

¿Son éstos los únicos métodos para obtener y mostrar las fotografías con Visual FoxPro?

No, hay varios otros métodos, pero los mostrados funcionan muy bien siempre y son muy rápidos. Y el último es a prueba de errores.

Conclusión:

Si usas Firebird lo conveniente es que guardes las fotografías (y cualquier otro contenido multimedia) dentro de la Base de Datos, porque al hacer así te aseguras que estén siempre a tu disposición y además disminuyes la probabilidad de vandalismo y si tal cosa llegara a ocurrir podrías muy fácilmente detectar al culpable.

Para guardar fotografías debes usar columnas de tipo BLOB, tanto las de subtipo 0 como las de subtipo 1 te servirán. El Firebird no guarda a las columnas de tipo BLOB en la tabla donde fueron declaradas esas columnas sino en otras páginas de la Base de Datos; en las columnas de tipo BLOB lo que se guarda es un puntero, una referencia, al lugar dentro de la Base de Datos en donde se encuentra el contenido.

Artículo relacionado:

El índice del blog Firebird21