Importante: Junto con este artículo y el siguiente (Redimensionar imágenes), recomiendo leer un artículo más nuevo: Redimensionar y guardar imágenes en ASP.NET, con el cual se resuelven algunos detalles de este.
A veces, es necesario permitirle al usuario cargar archivos desde su computadora, como imágenes, documentos, o archivos de cualquier tipo.
Por ejemplo, si estamos haciendo un sistema para una tienda, podemos permitirle al usuario cargar fotografías de los productos cuando los registra en el catálogo.
Lo que el usuario sube lo podemos guardar de dos formas: directamente en una carpeta de nuestra aplicación web ó en una tabla de una base de datos.
Comenzaré creando el markup de la página:
<form id="form1" runat="server"> <div> <div> <asp:RadioButton id="disco" runat="server" GroupName="guardar" Checked="true" Text="Guardar imagen en disco"/> <asp:RadioButton id="bd" runat="server" GroupName="guardar" Text="Guardar imagen en base de datos"/> </div> <p> <asp:Label AssociatedControlId="fileUploader1" runat="server" Text="Seleccionar una imagen:" /> <asp:FileUpload id="fileUploader1" runat="server" /> </p> <asp:Button id="cargarImagen" runat="server" Text="Cargar imágenes" OnClick="cargarImagen_Click"/> </div> </form>
- disco
- Guardar archivo en una carpeta de la aplicación web.
- bd
- Guardar archivo en la base de datos.
- fileUploader1
- Objeto
input
de tipofile
para cargar el archivo. - cargarImagen
- Botón que procesa el archivo y lo guarda según la opción seleccionada.
El código para el botón cargarImagen sería el siguiente:
protected void cargarImagenes_Click( object sender, EventArgs e) { try { if (fileUploader1.HasFile) { // Se verifica que la extensión sea de un formato válido string ext = fileUploader1.PostedFile.FileName; ext = ext.Substring(ext.LastIndexOf(".") + 1).ToLower(); string[] formatos = new string[] { "jpg", "jpeg", "bmp", "png", "gif" }; if (Array.IndexOf(formatos, ext) < 0) MensajeError("Formato de imagen inválido."); else if (disco.Checked) GuardarArchivo(fileUploader1.PostedFile); else GuardarBD(fileUploader1.PostedFile); } else MensajeError("Seleccione un archivo del disco duro."); } catch (Exception ex) { MensajeError(ex.Message); } }
Primero, se verifica que se haya seleccionado un archivo en el control fileUpload1
, checando su propiedad HasFile
. Después, se revisa la extensión del archivo (ya que estamos limitando la carga a imágenes solamente). Finalmente, dependiendo la opción que se seleccionó desde la página, invocaremos a un método para guardar el archivo en el disco duro o en la base de datos. En ambos métodos estamos enviando como parámetro un objeto HttpPostedFile
contenido en el control FileUpload
.
Guardar archivos en el disco duro
Guardar un archivo desde un control FileUpload
no tiene la menor complejidad. El mismo objeto HttpPostedFile
tiene un método para guardar en el disco duro, llamado (oh, sorpresa!) SaveAs
.
private void GuardarArchivo(HttpPostedFile file) { // Se carga la ruta física de la carpeta temp del sitio string ruta = Server.MapPath("~/temp"); // Si el directorio no existe, crearlo if (!Directory.Exists(ruta)) Directory.CreateDirectory(ruta); string archivo = String.Format("{0}\\{1}", ruta, file.FileName); // Verificar que el archivo no exista if (File.Exists(archivo)) MensajeError(String.Format( "Ya existe una imagen con nombre\"{0}\".", file.FileName)); else { file.SaveAs(archivo); } }
Guardar archivos en la base de datos
Una imagen, como cualquier archivo de nuestra computadora, está formada por un conjunto de bytes. En SQL, existen los tipos de datos BLOB (binary large object), usados para guardar esta clase de datos (archivos). En T-SQL de SQL Server, tenemos los tipos de dato IMAGE
y BINARY
, que nos permiten guardar archivos en la base de datos.
Nuestra imagen, contenida en el objeto HttpPostedFile
dentro de un objeto de clase FileStream
, deberá ser convertida a un conjunto de bytes para enviarlo a la base de datos. Dicho de otro modo, convertiremos el objeto de tipo Stream
a un arreglo de bytes.
También estoy guardando la extensión y el tipo de contenido (contentType) de la imagen, ya que estos datos muy probablemente me sirvan al momento de descargar el archivo de la base de datos, principalmente si trato con archivos de distinto tipo.
private static void GuardarBD(HttpPostedFile file) { // Nombre de la imagen string nombre = file.FileName.Substring( 0, file.FileName.LastIndexOf(".")); // Extensión del archivo string ext = nombre.Substring(nombre.LastIndexOf(".") + 1); // Tipo de contenido string contentType = file.ContentType; // Imagen convertida a arreglo de bytes byte[] imagen = new byte[file.InputStream.Length]; file.InputStream.Read(imagen, 0, imagen.Length); // Se insertan los valores en la base de datos SqlConnection cnx = GetConnection(); try { cnx.Open(); SqlCommand cmd = cnx.CreateCommand(); cmd.CommandText = "INSERT INTO Imagenes (nombre, imagen, extension, contentType) " + "VALUES (@nombre, @imagen, @ext, @contentType)"; cmd.Parameters.AddWithValue("@nombre", nombre); cmd.Parameters.AddWithValue("@imagen", imagen); cmd.Parameters.AddWithValue("@ext", ext); cmd.Parameters.AddWithValue("@contentType", contentType); cmd.ExecuteNonQuery(); } catch (Exception ex) { throw ex; } finally { if (cnx != null) { if (cnx.State == ConnectionState.Open) cnx.Close(); cnx.Dispose(); } } }
Al final, no es tan complicado crear un sistema de carga de archivos para el usuario.
A mi punto de vista, es mejor guardar las imágenes en una carpeta que subirlas a la base de datos. Sería más carga para el servidor de BD cargar ahí las imágenes, además de que se ocupa más procesamiento para descargarlas y nuevamente convertirlas a imagen. Es mejor guardar en el disco duro la imagen y en la base de datos, la ruta a dicha imagen.
Otra cosa, referente a imágenes: es muy recomendable redimensionarlas. Siguiendo con el ejemplo del catálogo de productos, si el usuario le tomó una fotografía al producto con su super cámara de 12 megapixeles y calidad ultra-mega-chido-cool, será muy pesado subirla al servidor y también demasiado molesto para el usuario descargar una imagen tan grande, solo para ver el producto. Será mejor ajustar la imagen a un tamaño estándar. Hablaré de esto en otra ocasión.
Hola, muy buena tu expliccion.
Pero se me presenta un problema al momento de leer el fileupload, al llegar a mi validacion me dice queno tiene ningun archivo asociado.
Me podrias ayudar como resovler esto??
Saludos
hola buen dia
la verdad excelente es una excelente explicacion, funciona muy bien solo hice algunos ajustes para que me funcionara en el proyecto que estoy trabajando, slo tengo una duda como recuperaria los archivos de manera inversa, por ejemplo los que se guardan en la bd o en el disco del servidor, te agradeceria mucho tu apoyo
de antemano muchas gracias
muy bueno el post
Probe el ejemplo y me da error, mde dice el mensajeerror no existe.
Alguein me puede ayurar a resolver esto?
Amis, jrtc, no puedo lograr hacer funcionar este ejemplo de subir imagenes redimensionadas a una carpeta con ASP.NET, por favor puedes ayudarme enviando tu ejemplo que ya funciona a mi email: silvia_rl9@hotmail.com.
gracias.
Permíteme hacer un ejemplo completo y te lo envío
Publiqué un nuevo artículo con el ejemplo. https://deployando.net/2013/09/30/redimensionar-y-guardar-imagenes-en-asp-net/
Disculpa la tardanza. Espero que te sirva.
Buen dia una pregunta como guardo un archivo pdf estoy trabajando con asp.net vb 2010 y mysql.. ya subo archivos a una carpeta temporal pero no se como guadarlos en la base de datos..
mi formulario tienes varios campos y una opcion para guardar el pdf .
si me pudiera ayudar por favor.
En tu base de datos necesitas un campo de tipo binario (binary o varbinary). El arreglo de bytes que generas desde la aplicación lo tienes que mandar a la base de datos como parámetro del mismo tipo.
SqlCommand cmd = connection.CreateCommand();
cmd.CommandText = «INSERT INTO … VALUES(@archivo, ….)»;
cmd.Parameters.AddWithValue(«@archivo», arreglo_bytes);
Hola Israel el link de tu código esta caído, lo podrías subir de nuevo gracias
Buen Post, estoy tratando de implementarlo sin embargo me da errores, si fueras tan amable de enviarme el ejemplo que ya funciona. Gracias de antemano.
Estoy trabajando en un ejemplo de este código, pero he estado muy ocupado en mi trabajo. En cuanto lo tenga listo lo subo
Publiqué un nuevo artículo, como lo menciono aquí al principio. https://deployando.net/2013/09/30/redimensionar-y-guardar-imagenes-en-asp-net/
Muy útil !
Tengo una duda. En caso de una modificación ¿Cómo se hace la carga de la imagen desde la ruta del servidor a el input type=»file»?.
El input de tipo file solo puede tener la imagen que el usuario va a enviar al servidor. Lo que puedes hacer es mostrar la imagen en una etiqueta img. Si el usuario quiere modificarla, usar el input para cargar una nueva. Pero no puedes poner la imagen que está en el servidor dentro del input.
La problematica esta muy bien definida …. pero creo que tambien analizar lo de la forma web …. cono nota si estan creando una pliacion web esta parte les ayudara un poco … pero asta el mometo de imprimir los msjs no se puede y marca error aqui —–>
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
yo recomiendo utilizar el ——>
catch (Exception e)
{
throw new Exception(e.Message);
}
Existe alguna forma de analizar el archivo antes de subirlo, esto para evitar que nos suban archivos con malware.