Cómo leer varios archivos a la vez usando la clase FileReader en JavaScript

Recientemente, tuve que trabajar en una característica muy simple de una aplicación que necesita leer varios archivos a la vez y concatenar su contenido en uno solo. Curiosamente, esta característica podría no ser tan fácil de implementar si utilizas métodos inadecuados.

En este artículo, te explicaré cómo leer fácilmente uno o varios archivos a la vez en JavaScript utilizando la clase FileReader y la API de Promesas.

Leer un solo archivo

Para comprender cómo vamos a proceder con la lectura de varios archivos, también explicaremos cómo funciona el proceso de lectura de un solo archivo. En este caso, usaremos la API Promises de JavaScript, ya que hace que el código sea más fácil de leer y comprender. En el marcado, tendremos una única entrada de archivo que le permite al usuario seleccionar un solo archivo del sistema. Con JavaScript, adjuntaremos un detector de eventos que reacciona al evento de cambio (cuando el usuario selecciona un archivo), cuando hay un archivo seleccionado, usaremos el método readFileAsText que creamos usando una simple promesa de JavaScript, así que cuando FileReader termina con la lectura del archivo, devolverá su contexto como resultado cuando se cumpla la promesa:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <label>Selecciona un archivo para leer de su sistema:</label>
        <input type="file" id="fileinput"/>

        <script>
            /**
             *  Promesa de JavaScript simple que lee un archivo como texto.
             **/
            function readFileAsText(file){
                return new Promise(function(resolve,reject){
                    let fr = new FileReader();

                    fr.onload = function(){
                        resolve(fr.result);
                    };

                    fr.onerror = function(){
                        reject(fr);
                    };

                    fr.readAsText(file);
                });
            }

            // Manejar fileupload
            document.getElementById("fileinput").addEventListener("change", function(ev){
                let file = ev.currentTarget.files[0];

                // Abortar la lectura del archivo si no se seleccionó ningún archivo
                if(!file) return;

                readFileAsText(file).then((fileContent) => {
                    // Imprimir el contenido del archivo en la consola
                    console.log(fileContent);
                });
            }, false);
        </script>
    </body>
</html>

Esta implementación es bastante útil y sencilla. Sin embargo, como está implementado ahora, puede resultar doloroso manejar varios archivos, especialmente cuando no sabes cuántos archivos se cargan.

Leer varios archivos a la vez

Ahora, si lo piensas, habrá casos en los que se necesites el contenido de varios archivos a la vez, por lo que si lees todos los archivos utilizando el método descrito anteriormente, el código de resultado será molesto de leer ya que estamos trabajando con devoluciones de llamada. Es por eso que vamos a aprovechar la API de Promesas usando el método Promises.all. Usaremos el mismo método readFileAsText del primer ejemplo, pero procederemos de manera diferente. Mantendremos la misma entrada de archivo único pero esta vez, este tiene el atributo multiple que permitirá al usuario seleccionar varios archivos a la vez. Cuando el usuario selecciona un archivo o varios archivos, se activará el detector de eventos adjunto (onchange). Almacenaremos una promesa del método readFileAsText de cada archivo seleccionado en una matriz. Una vez que recorramos todos los archivos, los activaremos con Promises.all que se cumplirá y activará una vez después de leer cada archivo:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <label>Selecciona varios archivos para leer de su sistema:</label>
        <input type="file" id="fileinput" multiple />

        <script>
            /**
             *  Promesa de JavaScript simple que lee un archivo como texto.
             **/
            function readFileAsText(file){
                return new Promise(function(resolve,reject){
                    let fr = new FileReader();

                    fr.onload = function(){
                        resolve(fr.result);
                    };

                    fr.onerror = function(){
                        reject(fr);
                    };

                    fr.readAsText(file);
                });
            }

            // Manejar múltiples cargas de archivos
            document.getElementById("fileinput").addEventListener("change", function(ev){
                let files = ev.currentTarget.files;
                let readers = [];

                // Abortar si no hubo archivos seleccionados
                if(!files.length) return;

                // Almacenar promesas en matriz
                for(let i = 0;i < files.length;i++){
                    readers.push(readFileAsText(files[i]));
                }
                
                // Activar promesas
                Promise.all(readers).then((values) => {
                    // Los valores serán una matriz que contiene un elemento.
                    // con el texto de cada archivo seleccionado
                    // ["File1 Content", "File2 Content" ... "FileN Content"]
                    console.log(values);
                });
            }, false);
        </script>
    </body>
</html>

¡Y eso es! Bastante fácil, ¿no? Recuerde que en este ejemplo usamos una configuración muy básica de la clase FileReader de JavaScript. En otros casos, es posible que necesite el contenido de los archivos como cadenas binarias, base64, etc., lo importante aquí es que tenga la idea de cómo leer varios archivos y obtener su contenido a la vez.

Que te diviertas ❤️!

Esto podria interesarte

Conviertete en un programador más sociable