如何在Dropzone.js中解压Zip文件并将内容导入上传器
解决Dropzone.js自动解压Zip并导入内部文件的问题
我之前在使用Dropzone.js开发多文件上传器时,遇到了完全一样的需求:希望上传Zip文件时自动解压,把内部文件直接导入Dropzone继续上传,同时复用已有的上传时长统计、服务器端处理逻辑。最开始尝试用zip.js处理解压,虽然能拿到Blob对象,但不知道怎么把这些Blob转换成Dropzone能识别的上传文件,折腾了一阵终于找到了解决方案,分享给大家:
初始尝试(踩坑代码)
最开始我写了这段代码,能成功解压拿到Blob,但卡在了如何将Blob导入Dropzone的环节:
var mediaDropzone = new Dropzone("#media-dropzone", { dictDefaultMessage: "Click or Drop files here to upload", dictInvalidFileType: "You can't upload files of this type.", }); Dropzone.options.mediaDropzone = false; mediaDropzone.options.acceptedFiles = ".csv,.xls,.xlsx,.txt,.zip"; mediaDropzone.on("sending", function(files, xhr, formData){ if (files.type === "application/zip"){ console.log(jQuery.type(files)); unzipBlob(files, function(unzippedBlob) { // logs the uncompressed Blob console.log(unzippedBlob); }); this.removeFile(files) } formData.append("fileuuid", files.upload.uuid); }); mediaDropzone.on("complete", function(files) { var _this = this; setTimeout(function(){ var acceptedFiles = _this.getAcceptedFiles(); var rejectedFiles = _this.getRejectedFiles(); for(var index = 0; index < acceptedFiles.length; index++) { var file = acceptedFiles[index]; console.log(jQuery.type(file)); if (file.status == "success") { appendContent(file.status, file.name, file.upload.uuid); _this.removeFile(file) } } if(acceptedFiles.length != 0) { alertify.success('Uploaded ' + acceptedFiles.length + ' files successfully.'); } if(rejectedFiles.length != 0) { alertify.error('Error uploading ' + rejectedFiles.length + ' files.'); } }, 2000); }); }); function unzipBlob(blob, callback) { // use a zip.BlobReader object to read zipped data stored into blob variable zip.createReader(new zip.BlobReader(blob), function(zipReader) { // get entries from the zip file zipReader.getEntries(function(entries) { // get data from the first file console.log(entries.length); for(var index = 0; index < entries.length; index++) { var file = entries[index]; file.getData(new zip.BlobWriter("text/plain"), function(data) { // close the reader and calls callback function with uncompressed data as parameter console.log("DATA::: " + data.data()); zipReader.close(); callback(data); }); }; }); }, onerror); }
最终可行方案
后来换成JSZip库,并且搞清楚了核心要点:需要把解压得到的Blob转换成File对象,再通过Dropzone的addFile()方法导入,这样就能自动触发上传流程了。修改后的核心代码如下:
if (files.type === "application/zip"){ var zip = new JSZip(); zip.loadAsync( files /* = file blob */) .then(function(zip) { return jQuery.map(Object.keys(zip.files), function(filename) { return zip.files[filename].async('blob').then(function (fileData) { // 过滤Mac系统生成的冗余隐藏文件,避免上传无用内容 if (filename.includes("_MAC")){ return; } else { // 将Blob包装成File对象,保留原文件名,让Dropzone识别为合法上传文件 var bloblextracted = new File([fileData], filename); // 调用addFile方法导入文件,自动触发Dropzone的上传流程 mediaDropzone.addFile(bloblextracted); } }) }) }, function() {alert("Not a valid zip file")}); // 移除原Zip文件,防止重复上传 this.removeFile(files); return; }
关键细节说明
- 使用
JSZip.loadAsync()异步加载Zip文件,不会阻塞页面交互 - 必须把Blob转换为
File对象,因为Dropzone的addFile()方法仅接受File类型参数 addFile()会自动触发Dropzone的上传流程,完美复用你之前写的上传逻辑- 添加了对Mac系统
_MACOSX相关文件的过滤,避免上传无用的隐藏文件
内容的提问来源于stack exchange,提问作者joe
相关产品推荐
相关产品推荐

