Almacenamiento de imágenes en Access

Fecha: 22/Jul/2004 (20/07/04)
Autor: MacK (mack0404-panorama@yahoo.com)

 

Tras la publicación del artículo "Acceso a imágenes en BD", he recibido múltiples consultas acerca de cómo guardar y recuperar imágenes en bases de datos Access. En este nuevo artículo veremos como podemos hacerlo utilizando C#.

 


Diseñando la base de datos

La primera duda que nos surge a la hora de guardar imágenes en una tabla de Access es qué tipo de datos utilizar para la columna. Ninguno de los tipos que se nos ofrece parece cuadrar con nuestras interés de guardar datos binarios. A diferencia de SQLServer, que nos ofrece un tipo Image predefinido, en Access deberemos optar por el tipo Objeto OLE. Este tipo de datos fue diseñado para almacenar objetos que cumpliesen con dicha especificación, en cuyos detalles no entraremos ahora. Nos basta con saber que los datos de un objeto OLE constan de dos partes principales: información acerca de cómo mostrar el objeto y otros datos nativos modificables por el servidor OLE que lo creó. Esto implica que almacenar un objeto OLE ocupe bastante más espacio  de lo que consume el objeto en si, ya que sus propios datos son solo unos pocos del total de la información almacenada.

Para que nuestra base de datos no crezca desmesuradamente, nosotros vamos a ignorar la especificación OLE y vamos a guardar únicamente la información de la imagen, con lo que la sobrecarga en cuanto a tamaño generada por Access será mucho menor.

En la base de datos de ejemplo que acompaña a este artículo encontraréis la tabla Imagenes, que contiene dos columnas: id, autonumérico que nos servirá de clave principal, e imagen, de tipo Objeto OLE y donde guardaremos los datos binarios de nuestra imagen.

Programa de ejemplo

Sentados los principios de cómo va a funcionar nuestro sistema de almacenamiento, pasemos a codificar. Puedes descargar el fichero adjunto a este texto (tienes el link al final de esta página) para ver una implementación muy sencilla de la teoría: una pequeña aplicación que permite guardar ficheros del disco duro en la base de datos Access y movernos por los registros, mostrando las imágenes en un pictureBox. Esté código ha sido escrito únicamente como ejemplo: no contiene control de errores, ni está estructurado convenientemente, y me he tomado algunas licencias en cuanto a nomenclatura, pero servirá para ver la teoría.

La aplicación esta formada por dos objetos: el formulario frmImagenes, que conforma la capa de presentación y la clase DBAccess, que implementa la capa de acceso a la base de datos. La base de datos ha de estar situada en el mismo directorio que el ejecutable, así que dependiendo de tu configuración del compilador deberás copiarla a bin/Debug o bin/Release tras compilar el código fuente.

Manos a la obra: guardando imágenes en la BD

Para almacenar una imagen en la base de datos, hemos de leer el archivo que la contiene en forma de stream binario. Para ello, utilizamos la clase BinaryReader, con la que a partir de un objeto FileStream podremos obtener los bytes que forman el archivo. En la aplicación de ejemplo, tras pulsar el botón "Guardar Imagen en BD" y elegir un archivo de tipo bmp, jpg o gif, se ejecuta el siguiente código (en la función btnGuardar_Click de frmImagenes):


System.IO.FileStream fs=new FileStream(ofdDataBase.FileName,FileMode.Open,FileAccess.Read);
System.IO.BinaryReader br = new System.IO.BinaryReader(fs);
byte [] abImagen=new byte[fs.Length];
br.Read(abImagen,0,(int)fs.Length);
br.Close();
fs.Close();

En primer lugar se crea un objeto FileStream apuntando al fichero que hemos seleccionado. Sobre este objeto se crea un BinaryReader, con el que podremos leer los bytes del la imagen y almacenarlos en un array de bytes (abImagen) del mismo tamaño que el fichero. Este array es el que enviamos a la clase DBAccess para ser almacenado mediante el método GuardarImagen:

public bool GuardarImagen(byte [] abImagen)
{
   OleDbCommand comm=new OleDbCommand("INSERT INTO imagenes (imagen) VALUES (?)",conn);
   OleDbParameter parImagen=new OleDbParameter("@imagen", OleDbType.VarBinary,abImagen.Length);
   parImagen.Value=abImagen;
   comm.Parameters.Add(parImagen);
   conn.Open();
   int iResultado=comm.ExecuteNonQuery();
   conn.Close();
   return Convert.ToBoolean(iResultado);
}

En este método, creamos un nuevo objeto OleDbCommand para ejecutar la INSERT en la base de datos. El parámetro que precisamos enviar es el array de bytes, por lo que en el tipo de dato del parámetro indicamos VarBinary (datos binarios de longitud variable).

La función devuelve un tipo booleano indicando si se ha efectuado o no la inserción en la base de datos. Como he comentado más arriba, no hay ningún tipo de control de errores en esta aplicación de ejemplo, algo que es indispensable en una real.

Obteniendo las imagenes de la base de datos

Para obtener la imagen guardada en la base de datos vamos a utilizar la función descrita en el artículo "Acceso a imagenes en BD" con algunas modificaciones, ya que Access no soporta procedimientos almacenados. He partido aquella función en dos para que resulte más clara. La primera, llamada ObtenerBytesImagen, está situada en la clase DBAccess, y obtiene el array de bytes a partir de los datos guardados en la columna imagen, a través de un objeto OleDbDataReader y su método GetValue, que nos devuelve un tipo Object conteniendo el array de bytes:

OleDbCommand comm=new OleDbCommand("SELECT TOP 1 ID,imagen FROM imagenes where ID" + sComparador + "?" + sOrder, conn);
comm.Parameters.Add(new OleDbParameter("ID", OleDbType.Integer, 0, "ID"));
comm.Parameters["ID"].Value=iImageID;
conn.Open();
OleDbDataReader dr=null;
dr=comm.ExecuteReader();
byte [] aBytes=null;
if (dr.Read())
{
   aBytes=(byte[])dr.GetValue(1);
   iImageID=dr.GetInt32(0);
}
conn.Close();
dr.Close();

La segunda función, obtenerImagen, está en frmImagenes, y se encarga de obtener un objeto System.Drawing.Image a partir del array de bytes, tal y como se explicaba en al artículo "Acceso a imagenes en BD". Este es el código que realiza dicha operación:

byte [] img = dba.ObtenerBytesImagen(eDir);
if (img!=null)
{ //Transformar los bytes en una imagen de nuevo
   MemoryStream ms = new MemoryStream();
   ms.Write(img, 0 ,img.GetUpperBound(0) + 1);
   picImagen.Image=System.Drawing.Image.FromStream(ms);
   ms.Close();
}

El código adicional que podéis ver en el fuente del ejemplo, y que no he comentado aquí, es propio de la aplicación. Las cuatro funciones aquí comentadas son las necesarias para almacenar y recuperar imágenes de la base de datos.

Conclusión

Como ves, el acceso y almacenamiento de imágenes en base de datos Access puede realizarse de una forma muy sencilla con VS.NET. Si tienes algún comentario acerca de este articulo no dudes en ponerte en contacto conmigo en mi dirección mack0404-panorama@yahoo.com

Y si el código te ha servido no olvides votarlo arriba, en la caja de PanoramaBox :)

MacK

 


ir al índice

Fichero con el código de ejemplo: mack_imagenesAccess.zip - 22 KB