Home > database >  Reading multiple files using file object
Reading multiple files using file object

Time:09-29

I am uploading multiple file(s) using a file reader

My aim is to get the base64 data of every files as array and output to console. But my code is always displaying empty array due to async

How can I display the base64 array when all filereaders are completely read?

My code is here

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
            <script>
    var file;
    var allfiles = [];

    function uploadForm() {
        Object.keys($('#file')[0].files).forEach(function(f){
          reader = new FileReader()
          console.log("---------")
          reader.readAsDataURL( $('#file')[0].files[f]);
          reader.onloadend = function(e) {
              allfiles.push(e.target.result);
              showMessage("Uploaded")
          };
        });
        console.log(JSON.stringify(allfiles))
        showMessage('Uploading file..<img width="20px;" src="https://c.tenor.com/XK37GfbV0g8AAAAi/loading-cargando.gif"/>');
    }
    
       /* Object.keys(files).forEach(function(f){
          alert(files[f])
          reader.readAsDataURL(files[f]);
        })*/

    function showMessage(e) {
        $('#progress').html(e);
        $('#file').val('');
    }
</script>
    
    
        <table cellpadding="5px">
        <tr>
            <td>Select File:</td>
            <td>
                <input id="file" type="file" value="" accept=".csv,.xlsx,.docx,.rtf,.pdf,.pptx,.txt" multiple>
            </td>
        </tr>
        <tr>
            <td colspan="2"><button onclick="uploadForm(); return false;">Upload</button>&emsp;</td>
        </tr>
        <tr>
            <td colspan="2">
                <div id="progress"></div>
            </td>
        </tr>
    </table>
    

CodePudding user response:

In your specific case, readAsDataURL is completing before reader.onloadend gets assigned a listener. Reordering will solve it:

reader.onloadend = function(e) {
    allfiles.push(e.target.result);
    showMessage("Uploaded")
};
reader.readAsDataURL( $('#file')[0].files[f]);

But this will not work for larger files (when readAsDataURL behaves async). I will suggest you start using Promises:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
    var file;
    var allfiles = [];

    function loadFile(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader()
            console.log("---------")
            reader.onerror = reject;
            reader.onload = (e) => resolve(e.target.result);
            reader.readAsDataURL(file);
        })
    }

    function filesToArray(files) {
        const out = [];
        for (let i = 0; i < files.length;   i) out.push(files[i]);
        return out;
    }

    function uploadForm() {

        const files = filesToArray($('#file')[0].files);
        let uploaded = 0;
        const promises = files.map(async f => {
                const result = await loadFile(f);
                showMessage(`${uploaded   }/${files.length}`);
                allfiles.push(result);
            });

        showMessage('Uploading file..<img width="20px;" src="https://c.tenor.com/XK37GfbV0g8AAAAi/loading-cargando.gif"/>');
        Promise.all(promises)
            .then(r => {
                console.log(allfiles);
                showMessage('Uploaded');
            })
            .catch(e => showMessage('Failed'));
    }

    function showMessage(e) {
        $('#progress').html(e);
        $('#file').val('');
    }
</script>

<table cellpadding="5px">
    <tr>
        <td>Select File:</td>
        <td>
            <input id="file" type="file" value="" accept=".csv,.xlsx,.docx,.rtf,.pdf,.pptx,.txt" multiple>
        </td>
    </tr>
    <tr>
        <td colspan="2"><button onclick="uploadForm(); return false;">Upload</button>&emsp;</td>
    </tr>
    <tr>
        <td colspan="2">
            <div id="progress"></div>
        </td>
    </tr>
</table>

  • Related