Procedimiento para guardar y leer imágenes desde una columna de BBDD en SQL Server con ASP.NET
El mismo procedimiento se puede utilizar para guardar cualquier tipo de archivo que no sea una imagen, el limite es de almacenamiento en disco y algunas extensiones de archivos que no podemos utilizar o a priori lo tenemos un poco más complicado. 🙂
En esta entrada vamos a crear una aplicación web con ASP.NET que nos valga de ejemplo para guardar y leer imágenes (archivos) directamente desde bases de datos.
Crear columna en base de datos
En SQL Server tenemos un tipo de datos image
preparado para almacenar imágenes. Se comporta como un tipo de datos binario de (2,147,483,647 bytes) de longitud así que es lo mismo que utilizar un tipo de datos varbinary
.
En el ejemplo utilizo un tipo de datos image
pero podéis utilizar un varbinary si no vais a guardar imágenes o si queréis especificar una precisión de datos diferente.
Crear un proyecto web
Paso 1. Abrir Visual Studio y crear un proyecto web vacío en C# o Visual Basic.
Paso 2. Hacer clic derecho sobre el proyecto y seleccionar la opción de Agregar > Nuevo elemento.
Paso 3. Seleccionar y agregar un Formulario Web Forms con el nombre default.aspx.
Guardar imagen en base de datos
Vamos a necesitar tres controles en la página principal (default.aspx). El primero es el control FileUpload
para permitir al usuario subir imágenes, el segundo será un tipo Image
para poder mostrar la imagen y por último un control de tipo Button
para guardar la imagen en la base de datos.
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="default.aspx.vb" Inherits="default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Guardar imagen en SQL Server</title> </head> <body> <form id="form1" runat="server"> <div> <asp:Image runat="server" ID="img" /> <br /> <asp:FileUpload ID="FileUpload1" runat="server" /> <br /> <asp:Button runat="server" ID="btnGuardar" Text="Guardar" /> </div> </form> </body> </html>
Cuando ejecutamos el proyecto (F5) la página default.aspx se verá de la siguiente manera.
El control FileUpload
le proporciona al usuario una forma de enviar archivos desde su equipo hasta el servidor. Podemos controlar bastantes propiedades como el tamaño permitido de los archivos o las extensiones.
En este ejemplo solo usaremos la propiedad PostedFile
para recuperar la imagen o el archivo en memoria.
FileUpload1.PostedFile.InputStream
Para guardar el archivo en la base de datos necesitamos convertir el Stream en un array de bytes. Para ello podemos usar la siguiente función auxiliar.
Private Function GetStreamAsByteArray(ByVal stream As Stream) As Byte() Dim streamLength As Integer = Convert.ToInt32(stream.Length) Dim fileData As Byte() = New Byte(streamLength) {} stream.Read(fileData, 0, streamLength) stream.Close() Return fileData End Function
Con la función anterior podemos crear la consulta SQL para guardar la imagen enviando por parámetro el array de bytes.
Private Sub InsertarImagen(ByVal Imagen As Byte()) Try Dim conexion As New SqlConnection("localhost") conexion.Open() Dim cmd As New SqlCommand("INSERT INTO PruebaImagen VALUES (@Imagen)", conexion) With cmd .Parameters.Add(New SqlParameter("@Imagen", SqlDbType.Image)).Value = Imagen End With cmd.ExecuteNonQuery() conexion.Close() Catch ex As Exception End Try End Sub
El código fuente completo de la página default.aspx es el siguiente:
Imports System.IO Imports System.Data Imports System.Data.SqlClient Partial Class index Inherits System.Web.UI.Page Protected Sub btnGuardar_Click(sender As Object, e As System.EventArgs) Handles btnGuardar.Click GuardarImagenSQL() End Sub Private Sub GuardarImagenSQL() Try If Not FileUpload1.HasFile Then Return End If Dim Imagen() As Byte = GetStreamAsByteArray(FileUpload1.PostedFile.InputStream) InsertarImagen(Imagen) Catch ex As Exception End Try End Sub Private Function GetStreamAsByteArray(ByVal stream As Stream) As Byte() Dim streamLength As Integer = Convert.ToInt32(stream.Length) Dim fileData As Byte() = New Byte(streamLength) {} stream.Read(fileData, 0, streamLength) stream.Close() Return fileData End Function Private Sub InsertarImagen(ByVal Imagen As Byte()) Try Dim conexion As New SqlConnection("Ruta de conexión con la base de datos") conexion.Open() Dim cmd As New SqlCommand("INSERT INTO PruebaImagen VALUES (@Imagen)", conexion) With cmd .Parameters.Add(New SqlParameter("@Imagen", SqlDbType.Image)).Value = Imagen End With cmd.ExecuteNonQuery() conexion.Close() Catch ex As Exception End Try End Sub End Class
Para asegurarnos de que la imagen o el archivo se ha guardado correctamente podemos abrir el gestor de base de datos y seleccionar las filas de la tabla afectada.
Si aparece el literal <Datos binarios> en las columnas es que se han guardado bien.
Leer imagen desde base de datos
El siguiente paso es recuperar la imagen desde la base de datos y mostrarla en el control Image
.
Para ello creamos una página imagen.aspx para gestionar el tratamiento de las imágenes.
Partial Class imagen Inherits System.Web.UI.Page Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load Try Dim conexion As New System.Data.SqlClient.SqlConnection("localhost") Dim cmd As New System.Data.SqlClient.SqlCommand Dim reader As System.Data.SqlClient.SqlDataReader cmd.CommandText = "SELECT TOP(1) FROM PruebaImagen" cmd.CommandType = System.Data.CommandType.Text cmd.Connection = conexion conexion.Open() reader = cmd.ExecuteReader() Response.ContentType = "img/png" If reader.Read Then Response.BinaryWrite(reader("IMAGEN")) End If conexion.Close() Catch ex As Exception End Try End Sub End Class
En el método load de la página principal (default.aspx) tendremos que escribir el siguiente código para redirigir a la página imagen.aspx.
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load img.ImageUrl = "imagen.aspx" End Sub