Imágenes en Base datos y Java

4
109518

Imágenes, Java/JDBC y MySQL

He recibido otra consulta que me ha gustado «¿como puedo almacenar y
recuperar imágenes en MySQL desde Java?». Hoy os vamos a contar paso a paso como
se puede hacer..

Muchos de vosotros que escribís preguntando por problemas en vuestros
programas, debéis ser comprensivos y tener en cuenta que recibimos muchas
peticiones diarias, no podemos atenderlas todas (el tiempo no da para tanto)
….. . Tratad de usar el foro y consultad los tutoriales disponibles, que
muchas cosas solicitadas las podéis encontrar ya resueltos.

Creación de la Tabla

En una de nuestras bases de datos, creamos una tabla (con
la consola de MySQL
) con los siguientes atributos

Insertar una fila en la tabla

Gracias a la consola, podemos insertar la primera imagen directamente:

Al pulsar sobre la columna de la imagen, automáticamente podemos
seleccionar un fichero a insertar.

Elegimos el desado

Como curiosidad de la foto, en las jardineras de mi ventana, podéis ver que
tengo habitualmente plantados melones (hay que disfrutar el placer de las cosas
simples) 😉

 

Programa de recuperación de los datos

El mejor modo de entender como realizar la recuperación de los datos es
leerse la propia especificación de JDBC que podéis encontrar en el Web de Sun:

http://java.sun.com/products/jdbc/download.html

Necesitamos por tanto, un objeto de tipo BLOB para acceder a los datos.
Volvemos a consultar la documentación, en este caso el API de JDBC
http://java.sun.com/j2se/1.3/docs/api/java/sql/Blob.html

Y escribimos un código sencillo (no tengáis en cuenta el diseño … ya que es
lamentable …. pero no quiero complicar su seguimiento)

  /*
 * imagenbbdd.java
 *
 * @author  Roberto Canales
 * Ejemplo de manipulación de imagenes en Base de Datos
 */

import java.io.*;
import javax.sql.*;
import java.sql.*;
import java.awt.*;

public class CImagenbbdd {
    public static void main(String[] args) {
        CImagenbbdd nuevo = new CImagenbbdd();
        nuevo.ejecuta();
    }

    public void depura(String param) {
        System.out.println("Mensaje depuración: " + param);
    }

    public void ejecuta() {

        long inicio = System.currentTimeMillis();

        Connection con = getConexion();

        long fin = System.currentTimeMillis() - inicio;
        depura("El tiempo transcurrido en conectar es " + fin + " milisegundos");

        InputStream imagenRecuperada = recuperaImagenBBDD(con);
        guardaImagenEnDisco(imagenRecuperada);

        fin = System.currentTimeMillis() - inicio;
        depura("El tiempo transcurrido completo es " + fin + " milisegundos");



    }

    public void guardaImagenEnDisco(InputStream imagenBuffer)
    {
        try // (esto es practicamente una copia de ficheros clasica)
        {
            File fichero = new File("c:\\melones.jpg");
            BufferedInputStream in = new BufferedInputStream(imagenBuffer);
            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(fichero));

            byte[] bytes = new byte[8096];
            int len = 0;

            depura("Copiamos el fichero");

            while ( (len = in.read( bytes ))> 0 )
            {
                out.write( bytes, 0, len );
            }

            out.flush();
            out.close();
            in.close();

            depura("Teminación del proceso con éxito");
        }
        catch(Exception e)
        {
            depura("Error al escribir en disco " + e.getMessage());
        }
    }


    public Connection getConexion() {
        Connection con = null;

        try {
            Driver d = (Driver)Class.forName("com.mysql.jdbc.Driver").newInstance();

            depura("Recuperamos conexión");
            con = DriverManager.getConnection("jdbc:mysql://localhost/tutoriales","","");
        }
        catch(Exception e) {
            depura("Error al recuperar conexion " + e.toString());
            return null;
        }

        return con;

    }

    public InputStream recuperaImagenBBDD(Connection con) {
        try {
            String consultaGenerada = "select * from imagenesbbdd limit 1";

            depura("Ejecutamos Statement");
            java.sql.Statement stmt = con.createStatement();

            depura("Ejecutamos sentencia " + consultaGenerada);
            ResultSet results = stmt.executeQuery(consultaGenerada);

            results.next();

            Blob campo = results.getBlob("imagen");
            return campo.getBinaryStream();
        }
        catch(Exception e) {
            depura("Error al recuperar el Stream");
        }

        return null;
    }

}
 

Como curiosidad, podéis ver los tiempos:

Mensaje depuración: Recuperamos conexión
Mensaje depuración: El tiempo transcurrido en conectar es 270 milisegundos
Mensaje depuración: Ejecutamos Statement
Mensaje depuración: Ejecutamos sentencia select * from imagenesbbdd limit 1
Mensaje depuración: Copiamos el fichero
Mensaje depuración: Terminación del proceso con éxito
Mensaje depuración: El tiempo transcurrido completo es 280 milisegundos

Supongo que aquí os daréis cuenta de la necesidad de usar pooles de
conexiones.

Podéis descargaros el código aquí

Otros enlaces de Interés

Podéis encontrar información valiosa sobre codificadores de distintos
formatos en el siguiente enlace.

http://www.geocities.com/marcoschmidt.geo/java-image-coding.html

Aunque también os deberías fijar en las nuevas APIs y filtros para el
procesamiento de imágenes que ya incorpora Java en las ultimas versiones.

http://javaalmanac.com/egs/javax.imageio/Graphic2File.html

Conclusiones

Como es de prever, escribir es similar … ver
setBinaryStream


   void escribeImagenEnBBDD(Connection con)
    {
        try {
              File fichero = new File("c:\\melones.jpg");
              FileInputStream streamEntrada = new FileInputStream(fichero);
              PreparedStatement pstmt = con.prepareStatement("insert into imagenesbbdd (nombre,imagen) values (?,?)");
              pstmt.setString(1, "melones.jpg");
              pstmt.setBinaryStream(2, streamEntrada, (int)fichero.length());
              pstmt.executeUpdate();
              pstmt.close();
              streamEntrada.close();

        }
        catch(Exception e) {
            depura("Error al escribir el Stream " + e.getMessage());
        }
    }

Lo bueno que tiene Java es lo fácil que nos hace el trabajo, con la
impresionante librería de clases que proporciona. El arte es saber encontrar los
recursos con velocidad.

Superados los problemas técnicos, solo nos quedan los problemas de negocio
(capturar bien requisitos, hacer un análisis antes de lanzarlos a picar…) y la
capacidad de hacer buenos diseños ….. cosa que poca gente tiene tiempo para
poder hacer (y conocimientos debido a la falta de tiempo) .

Sobre el
Autor ..

4 COMENTARIOS

  1. public static void main(String[] args) throws Exception, IOException, SQLException {
    Class.forName(\\\»org.sqlite.JDBC\\\»);
    Connection conn= DriverManager.getConnection(\\\»jdbc:sqlite:bd.sqlite\\\»);
    PreparedStatement ps = conn.prepareStatement(\\\»insert into tutabla(tuscampos) values (?)\\\»);
    try {
    conn.setAutoCommit(false);
    File archivo = new File(\\\»rutadetuimagen\\\»);
    FileInputStream f = new FileInputStream(archivo);
    ps.setBinaryStream(1, f, (int) archivo.length());
    ps.executeUpdate();
    conn.commit();
    } finally {
    ps.close();
    }

    }

  2. Ante todo felicitarte por este magnifico tutorial ya que es muy dificil encotrar en la red informacion asi y bien detallada, no como otros que te ponen un super codigo tal vez copiado de sun y se las dan de que saben mucho.
    muy bien sigue asi

  3. QUE ESTOY HACIENDO MAL?.

    PORFA NECESITO AYUDA NO SE QUE ESTOY HACIENDO MAL, HE BUSCADO POR TODOS LADOS Y NO CONSIGO SOLUCION A MI ERROR.

    public void guardar_Cal() throws Exception{
    try {
    File file = new File(«src/archivos/calibraciones_file.calibracion»);
    FileInputStream fis = new FileInputStream(file);
    long datos = file.lastModified();
    Date fecha = new Date(datos);
    Connection accesoBBDD=miConexion.conectar();
    PreparedStatement ps = accesoBBDD.prepareStatement(«INSERT INTO digitalcal(FechaCal, Nombre, Calibraciones) VALUES(‘»+fecha.toString()+»‘, ‘erick’, ‘?’)»);
    ps.setBinaryStream(1, fis, file.length());
    ps.executeUpdate();
    ps.close();
    accesoBBDD.close();
    fis.close();
    } catch (Exception e) {
    e.printStackTrace();
    }

    SIEMPRE ME SALE ESTE ERROR

    java.lang.ArrayIndexOutOfBoundsException: 0
    at com.mysql.jdbc.PreparedStatement.setBinaryStream(PreparedStatement.java:3286)
    at com.mysql.jdbc.PreparedStatement.setBinaryStream(PreparedStatement.java:5269)

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad