Descargar Archivos con Javascript

Hace unos años escribí un artículo explicando como crear y descargar un archivo usando solo Javascript, y creo que es buen momento para revisarlo y actualizar algunas cosas que han cambiado desde entonces. Comenzaremos por crear un simple archivo de texto y descargarlo directamente desde código Javascript. Con esto cubriríamos el caso de uso base.…


Hace unos años escribí un artículo explicando como crear y descargar un archivo usando solo Javascript, y creo que es buen momento para revisarlo y actualizar algunas cosas que han cambiado desde entonces.

Comenzaremos por crear un simple archivo de texto y descargarlo directamente desde código Javascript. Con esto cubriríamos el caso de uso base. Luego, en el próximo artículo probaremos nuestra función de descarga generando primero un archivo XML, también desde Javascript, y luego una imagen a partir de un elemento canvas.

Descargar un archivo de texto simple

Primero crearemos un archivo de texto simple, tomando datos de un formulario. Este será el HTML para el ejemplo:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>VT - Descargar Archivos con Javascript</title>
    <style>
        .datos-personales{
            display: grid;
            grid-template-columns: 180px 200px;
            row-gap: 1rem;
            margin: 1rem;
            line-height: 1.5rem;
            font-family: Arial, Helvetica, sans-serif;
        }
    </style>
</head>
<body>
    <form class="datos-personales">
        <label for="nombre">Nombre:</label>
        <input id="nombre" type="text" value="Juan Carlos Gonzales"/>
        <label for="fecha">Fecha de Nacimiento:</label>
        <input id="fecha" type="date" value="1982-01-01"/>
        <label for="telefono">Teléfono:</label>
        <input id="telefono" type="tel" value="0800-999.0123"/>
        <label for="direccion">Dirección:</label>
        <textarea id="direccion" rows="4">Av. Principal con calle 18, Urb. La Esmeralda. Edificio Roma, Apto. #12-B</textarea>
        <button type="button" id="boton-descargar">Descargar Archivo</button>
    </form>
    <script src="script.js"></script>
</body>
</html>

Si vas a seguir el ejemplo, guarda este código con algún nombre apropiado (index.html) y ábrelo en el navegador. Como el código es muy simple, no es necesario que lo subas a un servidor para probar. En el navegador verás algo como esto (incluye datos de ejemplo para probar):

Representación del formulario en el navegador

Ahora veamos el código para generar el archivo:

document.addEventListener('DOMContentLoaded', (e)=>{

    /**
     * Genera un objeto Blob, que contiene un archivo de texto.
     * @returns Blob Objeto de tipo Blob con el archivo de texto.
     */
    const generarBlobTexto = function(){

        //Una forma simple de concatenar texto: usando un array!
        const partes = [];

        partes.push('Datos Personales:\n');
        partes.push('Nombre: ');
        partes.push(document.querySelector('#nombre').value);
        partes.push('\n');
        partes.push('Fecha de Nacimiento: ');
        partes.push(document.querySelector('#fecha').value);
        partes.push('\n');
        partes.push('Teléfono: ');
        partes.push(document.querySelector('#telefono').value);
        partes.push('\n');
        partes.push('Dirección: ');
        partes.push(document.querySelector('#direccion').value);

        const blobArchivo = new Blob(partes, { type: 'text/plain'} );

        return blobArchivo;

    }

    /**
     * Inicia la descarga del archivo en el navegador. 
     * Dependiendo de la configuración del navegador, 
     * este descarga el archivo automáticamente, o mostrará
     * el cuadro de dialogo "Guardar Cómo"
     * @param {Blob} archivo Objeto tipo Blob para descargar. 
     * @param {string} nombre Nombre por defecto para el archivo 
     */
    const descargarArchivo = function(archivo, nombre){

        //Solo para probar...
        console.log(archivo);

    }

    //Al hacer clic: generar el archivo
    document.querySelector('#boton-descargar').addEventListener('click', (e) =>{

        //Primero generamos el Blob
        const archivo = generarBlobTexto();

        //Y luego lo descargamos
        descargarArchivo(archivo, 'datosPersonales.txt');

    });

});

Y veamos como funciona. Primero, esperamos a que el navegador haya cargado todo el HTML (cuando se dispara el evento DOMContentLoaded), y entonces definimos dos funciones: la primera es generarBlobTexto, y se encargará de tomar algunos valores de los inputs en pantalla, y a partir de estos generar el archivo de texto (devuelve un objeto de tipo Blob, que a efectos prácticos, diremos que es un archivo).

La segunda función, descargarArchivo, aun no tiene código, por ahora solo enviará el Blob a la consola. Si quieres probar, guarda este código con el nombre script.js, en la misma carpeta que el archivo html, y ejecútalo de nuevo en el navegador: Si abres la consola del navegador (presionando F12, en casi cualquier navegador), y presionas el botón Descargar Archivo, verás que se genera un blob y se muestra en la consola:

Consola del navegador, mostrando el objeto Blob generado

Ahora vamos a programar la función que descarga el archivo:

    /**  
     * Inicia la descarga del archivo en el navegador. 
     * Dependiendo de la configuración del navegador, 
     * este descargará el archivo automáticamente, o mostrará
     * el cuadro de dialogo "Guardar Cómo"
     * @param {Blob} archivo Objeto tipo Blob para descargar. 
     * @param {string} nombre Nombre por defecto para el archivo
     */
    const descargarArchivo = function(archivo, nombre){

        console.log(archivo);
        
        //Creamos un link
        const guardar = document.createElement('a');
        //Le asigna el ObjectURL que "apunta" al Blob
        guardar.href = URL.createObjectURL(archivo);
        //Preferiblemente descargar (con el nombre indicado), 
        //sino, entonces que por lo menos abra en otra ventana
        guardar.download = nombre || 'archivo.dat'; 
        guardar.target = '_blank'; 
        
        //Simulamos un clic del usuario
        //Nota: no es necesario agregar el link al DOM
        var eventoClic = new MouseEvent('click', {
            'view': window,
            'bubbles': true,
            'cancelable': true
        });
        guardar.dispatchEvent(eventoClic);

        //Al final removemos el ObjectURL para liberar recursos
        URL.revokeObjectURL(guardar.href);

    }

Probamos el código nuevamente, y al presionar «Descargar Archivo» se muestra el cuadro de diálogo de descarga:

Cuadro de Diálogo de descarga de archivo

Bueno, el código ya funciona… pero queremos saber cómo, ¿o no?

Primero, la función descargarArchivo requiere dos parámetros. El primero es un blob (aunque funcionará igual con un File), que contiene el archivo que queremos descargar. El segundo parámetro es el nombre que queremos que el archivo tenga por defecto, aunque el usuario puede cambiarlo si al comenzar la descarga le aparece el cuadro de dialogo «Guardar Cómo».

Al ejecutarse la función, se genera un elemento html que representa un link. A este link le asigna como propiedad href un ObjectURL generado para el archivo (así, al hacer clic, el link «abrirá» el archivo deseado). La propiedad download se usa para indicar el nombre por defecto del archivo, y cuando un link tiene esa propiedad asignada, le está indicando al navegador que «preferimos» que descargue el archivo en lugar de abrirlo o navegar a él (y digo «preferimos» porque es solo una sugerencia al navegador, al final el usuario puede forzar uno u otro comportamiento). Y en caso de que el navegador decida ignorar la sugerencia, y «abra» el link, indicaremos mediante la propiedad target que queremos que el archivo se abra en una nueva ventana o pestaña. Esto último también es una «sugerencia», que el navegador puede o no cumplir.

Para terminar, generamos un nuevo evento de tipo clic, y lo ejecutamos mediante la función dispatchEvent del link, con lo cual realmente se abrirá o descargará el archivo. Una vez descargado el archivo, usamos la función revokeObjectURL para eliminar el ObjectURL que le asignamos al link, y así liberar recursos.

Próximo artículo: descargar un XML y una imagen

En el próximo artículo, veremos este mismo proceso, pero descargando primero un archivo XML generado del mismo modo que el archivo de texto, y luego un archivo de imagen generado también desde el navegador, desde un canvas.

Derecho de uso

Los contenidos generados por el autor de este artículo (explicaciones, código fuente, y archivos adjuntos creados por el autor) están disponibles bajo licencia CC BY-SA 3.0, y pueden ser usados, derivados y compartidos bajo los términos indicados en la misma. Los contenidos no generados por el autor de este artículo son propiedad de sus respectivos dueños y están regidos por las licencias que estos hayan dispuesto.

,

Una respuesta a “Descargar Archivos con Javascript”

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Soluciones claras y simples



Ing. Industrial, dedicado a la programación en ASP.NET+VB, SQL y Javascript+AJAX; y un poco de Android, Kotling, y Unity 🙂
Valencia, Venezuela



¿QUIERES APOYARME?

¿Te ha sido de ayuda alguno de mis artículos? Generar contenido técnico requiere de tiempo y esfuerzo. Con tu colaboración me puedes ayudar a mantener mi blog activo y actualizado. Si quieres y puedes apoyarme has clic aquí:

https://paypal.me/roimergarcia


ENTRADAS RECIENTES