如何使用zip.js将多个文件添加到一个zip压缩包中?

8
我正在使用javascript zip.js库。我已经搜索了所有地方,但是找不到添加多个文件到zip的示例。
这是我的代码,但它生成了一个“损坏”的zip文件。
var len = results.rows.length, i;
var k=1;
zip.createWriter(new zip.BlobWriter(), function(writer) {
    for (i = 0; i < len; i++){
        // get the image url from a sqlite request
        url = results.rows.item(i).url;


        var img = new Image();
        img.onload = function() {
            var a = document.createElement('a');
            a.href = this.src;
            var filename= a.pathname.split('/').pop(); // filename.php
            timest = new Date().getTime();
            // use a TextReader to read the String to add

                writer.add(timest+".jpg", new zip.Data64URIReader(getBase64Image(img)), function() {
                // onsuccess callback
                    k++;
                    if(k==len){
                        setTimeout(function(){
                        writer.close(function(blob) {

                            // blob contains the zip file as a Blob object
                            $('#test').attr("href", window.URL.createObjectURL(blob));
                            $('#test').attr("download", "woeii.zip");

                        });
                        },1000);
                    }
                }, function(currentIndex, totalIndex) {
                // onprogress callback
                });



        };
        img.src = url;
    }
});

有什么想法让它工作吗? :)
2个回答

7
如果您正在寻找处理多个文件的代码示例,请看这里。然后您可以查看源代码
这是演示的关键源代码(略微修改):
var obj = this;
var model = (function() {
    var zipFileEntry, zipWriter, writer, creationMethod, URL = obj.webkitURL || obj.mozURL || obj.URL;

    return {
        setCreationMethod : function(method) {
            creationMethod = method;
        },
        addFiles : function addFiles(files, oninit, onadd, onprogress, onend) {
            var addIndex = 0;

            function nextFile() {
                var file = files[addIndex];
                onadd(file);
                // Modified here to use the Data64URIReader instead of BlobReader
                zipWriter.add(file.name, new zip.Data64URIReader(file.data), function() {
                    addIndex++;
                    if (addIndex < files.length)
                        nextFile();
                    else
                        onend();
                }, onprogress);
            }

            function createZipWriter() {
                zip.createWriter(writer, function(writer) {
                    zipWriter = writer;
                    oninit();
                    nextFile();
                }, onerror);
            }

            if (zipWriter)
                nextFile();
            else if (creationMethod == "Blob") {
                writer = new zip.BlobWriter();
                createZipWriter();
            } else {
                createTempFile(function(fileEntry) {
                    zipFileEntry = fileEntry;
                    writer = new zip.FileWriter(zipFileEntry);
                    createZipWriter();
                });
            }
        },
        getBlobURL : function(callback) {
            zipWriter.close(function(blob) {
                var blobURL = creationMethod == "Blob" ? URL.createObjectURL(blob) : zipFileEntry.toURL();
                callback(blobURL);
                zipWriter = null;
            });
        },
        getBlob : function(callback) {
            zipWriter.close(callback);
        }
    };
})();

用法: 假设存在一个<a id="downloadLink">下载</a>元素,以便在准备好后提供下载。

// Prepare your images
var files = [];
for (i = 0; i < len; i++) {

    // Get the image URL from a SQLite request
    var url = results.rows.item(i).url;

    (function(url){
        var img = new Image();
        img.onload = function() {
            // Add to file array [{name, data}]
            var a = document.createElement('a');
            a.href = this.src;
            var filename= a.pathname.split('/').pop();

            console.log("Loaded file " + filename);
            files.push({name: filename, data: getBase64Image(img) });
        }
        img.src = url;
    })(url);
}

// Wait for the image to load
var check = setInterval(function(){
    if(files.length==images.length) {
        clearInterval(check);

        // Set the mode
        model.setCreationMethod("Blob");

        // Add the files to the zip
        model.addFiles(files, 
            function() {
                // Initialise Method
                console.log("Initialise");
            }, function(file) {
                // OnAdd
                console.log("Added file");
            }, function(current, total) {
                // OnProgress
                console.log("%s %s", current, total);
            }, function() {
                // OnEnd
                // The zip is ready prepare download link
                // <a id="downloadLink" href="blob:url">Download Zip</a>
                model.getBlobURL(function(url) {
                    document.getElementById("downloadLink").href = url;
                    document.getElementById("downloadLink").style.display = "block";
                    document.getElementById("downloadLink").download = "filename.zip";
                });
            });

    }
}, 500);

您可以使用示例源代码添加进度指示器。 希望这能帮到您,这种方法的好处是如果将其制作成自己的JS文件,则可以轻松地重复使用zip模型。


另一个想法:我假设您正在使用getBase64Image函数从这里,如果是这样,并且您仍然遇到损坏问题,请尝试修改返回值为简单的return dataURL;并注释掉.replace(...,因为Data64URIReader可能需要前缀。

谢谢! :) 这似乎有效。我还有一个问题,只有最后一张图片在zip中保存了多次。我认为这是模型函数引起的。我正在研究它。 - Paul Fournel
我几分钟前对代码进行了更改,您可能还没有收到更改。在图像加载器中,请确保URL前面有“var”,否则“onload”函数将无法正确获取变量。 - Scott
问题确实出在URL变量上。由于onload函数的异步执行,它仍然会多次保存最后一张图片。我使用匿名函数解决了这个问题,将其包裹在img.onload周围。再次感谢您:) 如果没有您的帮助,我可能会卡在那里几天! - Paul Fournel

5
以下是使用RAM存储的削减版演示,与此演示相同。假定zip.js、z-worker.js和deflate.js位于与以下两个文件相同的目录中,并且附带FileSaver.js

注意:这不是生产就绪的代码!这是我制作的一个基本演示,以便我可以弄清楚发生了什么。如果您以编程方式生成并保存zip,则可能需要实现nextFile()迭代器来避免使用空文件填充zip时出现竞争条件(请参见https://dev59.com/P2_Xa4cB1Zd3GeqP0Fkg#29738675)。

demo.html:

<li>
    add files into the zip
    <input type="file" multiple id="file-input" onchange="addFiles(this.files)">
</li>
<li>
    download the zip file
    <a href="#" onclick="saveZip()">Download</a>
</li>

<script type="text/javascript" src="zip.js"></script>
<script type="text/javascript" src="demo.js"></script>
<script type="text/javascript" src="FileSaver.js"></script>

demo.js:

var zipWriter;

function addFiles(files) {
    writer = new zip.BlobWriter();
    zip.createWriter(writer, function(writer) {
        zipWriter = writer;
        for (var f = 0; f < files.length; f++) {
            zipWriter.add(files[f].name,
            new zip.BlobReader(files[f]), function() {});
        }
    });
}

function saveZip() {
    zipWriter.close(function(blob) {
        saveAs(blob, "Example.zip"); // uses FileSaver.js
        document.getElementById("file-input").value = null; // reset input file list
        zipWriter = null;
    });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接