How to read multiple files at once using the FileReader class in JavaScript

Recently, I had to work on a very simple feature of an application that needs to read multiple files at once and concatenate its content into a single one. Curiously, such a feature could be not so easy to implement if you use inadequate methods.

In this article, I will explain to you how to easily read single or multiple files at once in JavaScript using the FileReader class and the Promises API.

Reading a single file

To understand how we are going to proceed reading multiple files, we will explain as well how the process of reading a single file works. In this case, we will use the Promises API of JavaScript, as it makes the code way easier to read and understand. In the markup, we will have a single file input that allows the user to select a single file from the system. With JavaScript, we'll attach an event listener that reacts to the change event (when the user selects a file), when there's a selected file, we'll use the readFileAsText method that we created using a simple JavaScript promise, so when the FileReaders finishes with the reading of the file, it will return its context as a result when the promise is fulfilled:

<!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>Select a file to read from your system:</label>
        <input type="file" id="fileinput"/>

        <script>
            /**
             *  Simple JavaScript Promise that reads a file as text.
             **/
            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);
                });
            }

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

                // Abort file reading if no file was selected
                if(!file) return;

                readFileAsText(file).then((fileContent) => {
                    // Print file content on the console
                    console.log(fileContent);
                });
            }, false);
        </script>
    </body>
</html>

This implementation is pretty useful and straightforward. However, as it's implemented now, it can become painful to handle multiple files especially when you don't know how many files are uploaded.

Reading multiple files at once

Now, if you think about it, there will be cases when the content of multiple files are needed at once, so if you read every file using the previously described method, the result code will be painful to read as we are working with callbacks. That's why we are going to take advantage of the Promises API using the Promises.all method. We will use the same readFileAsText method from the first example, but we are going to proceed differently. Keep the same single file input but this time, it has the multiple attribute that will allow the user to select multiple files at once. When the user selects a file or multiple files, the attached event listener (onchange) will be triggered. We will store a promise of the readFileAsText method from every selected file into an array. Once we loop through all the files, we'll trigger them with Promises.all that will be fulfilled and triggered once after reading every single file:

<!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>Select multiple files to read from your system:</label>
        <input type="file" id="fileinput" multiple />

        <script>
            /**
             *  Simple JavaScript Promise that reads a file as text.
             **/
            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);
                });
            }

            // Handle multiple fileuploads
            document.getElementById("fileinput").addEventListener("change", function(ev){
                let files = ev.currentTarget.files;
                let readers = [];

                // Abort if there were no files selected
                if(!files.length) return;

                // Store promises in array
                for(let i = 0;i < files.length;i++){
                    readers.push(readFileAsText(files[i]));
                }
                
                // Trigger Promises
                Promise.all(readers).then((values) => {
                    // Values will be an array that contains an item
                    // with the text of every selected file
                    // ["File1 Content", "File2 Content" ... "FileN Content"]
                    console.log(values);
                });
            }, false);
        </script>
    </body>
</html>

And that's it! Quite easy isn't it? Remember that in this example we used a very basic configuration of the FileReader class of JavaScript. In other cases, you may need the content of files as binary strings, base64, and so on, the important thing here is that you get the idea of how to read multiple files and obtain its content at once.

Happy coding ❤️!

This could interest you

Become a more social person