最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

html - Read Multiple Files With JavaScript and Wait for Result - Stack Overflow

programmeradmin0浏览0评论

I would like to start by saying that (coming from c++ and python) I am totally new to JS and so I welcome any wise suggestions regarding my code.

I wish to read a number of files using the HTML5 file API, then open them with JS, perform some manipulation and download the results zipped. My problem is that reading the files seems to be an asynchronous operation, and I don't really see an elegant way to wait for them all to finish and then zip the results.

One possible solution is presented here: but I am wondering if one can do better than using a global flag.

I also have a problem with retrieving the result from the async function as I have no idea how to get back new_file_list in changeCharsInFiles.

Thank you!

Code example: HTML:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" href=".3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body >
        <div class="container">
            <div class="jumbotron">
                <h3>Add Files Here</h3>
                <input type="file" id="the-file-field" multiple>
            </div>
        </div>
        <script src=".12.4/jquery.min.js"></script>
        <script src=".1.5/jszip.min.js"></script>
        <script src=".js"></script>
        <script>
         ########### SEE JS BELOW #####################
    </script>
</body>

JS:

if (window.File && window.FileReader && window.FileList && window.Blob) {

                //functions
                function zipMyFilesAndSave(file_list){

                    var zip = new JSZip();
                    for (var i = 0; i<file_list.length; i+=1)
                    {
                        zip.file(file_list[i].name, file_list[i]  );
                    }
                    zip.generateAsync({type:"blob"}).then(
                    function (blob) {                                      
                        saveAs(blob, "hello.zip");                         
                    }, 
                    function (err) {
                        jQuery("#blob").text(err);
                    }); 
                }

                function changeCharsInFiles(file_list){
                    var new_file_list = [];

                    for (var i = 0; i<file_list.length; i+=1)
                    {
                        var file = file_list[i]

                        var reader = new FileReader();
                        reader.onload = function() {
                            //alert(reader.result);
                            var txt  = reader.result;
                            console.log("txt: ",txt)

                            var new_txt = ""
                            var allTextLines = txt.split(/\r\n|\n/);

                            for (var j = 0; j<allTextLines.length; j+=1)
                            {
                                var res = allTextLines[j].replace("a", "A");
                                res = res.replace("b", "B");
                                res = res.replace("c", "C");
                                res = res.replace("d", "D");

                                new_txt += res + "\n"

                            }
                            console.log("new_txt: ", new_txt)
                            var new_file = new Blob([new_txt], {type: "text/plain"});

                            new_file_list.push(new_file); //<---------------------------how do I get this back?
                        }
                        reader.readAsText(file);    

                    }


                    return new_file_list;
                }

                //watcher
                $( "#the-file-field" ).change(function() {
                    console.log("files have been chosen")
                    var file_list = this.files
                    file_list = changeCharsInFiles(file_list)
                    zipMyFilesAndSave(file_list)    
                });


            } else {
                alert('The File APIs are not fully supported in this browser.');
            }

I would like to start by saying that (coming from c++ and python) I am totally new to JS and so I welcome any wise suggestions regarding my code.

I wish to read a number of files using the HTML5 file API, then open them with JS, perform some manipulation and download the results zipped. My problem is that reading the files seems to be an asynchronous operation, and I don't really see an elegant way to wait for them all to finish and then zip the results.

One possible solution is presented here: https://stackoverflow.com/a/17491515 but I am wondering if one can do better than using a global flag.

I also have a problem with retrieving the result from the async function as I have no idea how to get back new_file_list in changeCharsInFiles.

Thank you!

Code example: HTML:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body >
        <div class="container">
            <div class="jumbotron">
                <h3>Add Files Here</h3>
                <input type="file" id="the-file-field" multiple>
            </div>
        </div>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js"></script>
        <script src="http://cdn.jsdelivr.net/g/filesaver.js"></script>
        <script>
         ########### SEE JS BELOW #####################
    </script>
</body>

JS:

if (window.File && window.FileReader && window.FileList && window.Blob) {

                //functions
                function zipMyFilesAndSave(file_list){

                    var zip = new JSZip();
                    for (var i = 0; i<file_list.length; i+=1)
                    {
                        zip.file(file_list[i].name, file_list[i]  );
                    }
                    zip.generateAsync({type:"blob"}).then(
                    function (blob) {                                      
                        saveAs(blob, "hello.zip");                         
                    }, 
                    function (err) {
                        jQuery("#blob").text(err);
                    }); 
                }

                function changeCharsInFiles(file_list){
                    var new_file_list = [];

                    for (var i = 0; i<file_list.length; i+=1)
                    {
                        var file = file_list[i]

                        var reader = new FileReader();
                        reader.onload = function() {
                            //alert(reader.result);
                            var txt  = reader.result;
                            console.log("txt: ",txt)

                            var new_txt = ""
                            var allTextLines = txt.split(/\r\n|\n/);

                            for (var j = 0; j<allTextLines.length; j+=1)
                            {
                                var res = allTextLines[j].replace("a", "A");
                                res = res.replace("b", "B");
                                res = res.replace("c", "C");
                                res = res.replace("d", "D");

                                new_txt += res + "\n"

                            }
                            console.log("new_txt: ", new_txt)
                            var new_file = new Blob([new_txt], {type: "text/plain"});

                            new_file_list.push(new_file); //<---------------------------how do I get this back?
                        }
                        reader.readAsText(file);    

                    }


                    return new_file_list;
                }

                //watcher
                $( "#the-file-field" ).change(function() {
                    console.log("files have been chosen")
                    var file_list = this.files
                    file_list = changeCharsInFiles(file_list)
                    zipMyFilesAndSave(file_list)    
                });


            } else {
                alert('The File APIs are not fully supported in this browser.');
            }
Share Improve this question asked May 23, 2018 at 10:25 user140832user140832 731 silver badge3 bronze badges 1
  • You can use a callback. function longTaking() {setTimeout({callYourFunction},1000). setTimeout() is just an example to demo your fileReading. – deEr. Commented May 23, 2018 at 10:32
Add a comment  | 

1 Answer 1

Reset to default 19

Try reading up on the Promise class, it was developed to make asynchronous operations easier:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

In your case, you could use it like this:

function changeCharsInFiles(file_list){
    let promises = [];
    for (let file of file_list) {
        let filePromise = new Promise(resolve => {
            let reader = new FileReader();
            reader.readAsText(file);
            reader.onload = () => resolve(reader.result);
        });
        promises.push(filePromise);
    }
    Promise.all(promises).then(fileContents => {
        // fileContents will be an array containing
        // the contents of the files, perform the
        // character replacements and other transformations
        // here as needed
    });
}

This is just a rough outline of the solution. I'd suggest you experiment a bit with Promises first (it can be a fairly deep topic) to figure out the basic principles, and then apply something like the above.

发布评论

评论列表(0)

  1. 暂无评论