有没有一种使用JavaScript压缩文件的方法?例如,在Yahoo邮箱中选择下载电子邮件的所有附件时,会将它们压缩并下载为一个zip文件。JavaScript能够实现吗?如果可以,请提供一个编程示例。
我发现了一个叫做jszip的库来完成这个任务,但它存在已知而未解决的问题。
如何解决这个问题?
有没有一种使用JavaScript压缩文件的方法?例如,在Yahoo邮箱中选择下载电子邮件的所有附件时,会将它们压缩并下载为一个zip文件。JavaScript能够实现吗?如果可以,请提供一个编程示例。
我发现了一个叫做jszip的库来完成这个任务,但它存在已知而未解决的问题。
如何解决这个问题?
JSZip多年来一直在更新。现在你可以在它的GitHub代码库上找到它。
它可以与FileSaver.js一起使用。
你可以使用npm来安装它们:
npm install jszip --save
npm install file-saver --save
然后导入并使用它们:
import JSZip from 'jszip';
import FileSaver from 'file-saver';
const zip = new JSZip();
zip.file('idlist.txt', 'PMID:29651880\r\nPMID:29303721');
zip.generateAsync({ type: 'blob' }).then(function (content) {
FileSaver.saveAs(content, 'download.zip');
});
您将下载一个名为download.zip的压缩文件,解压后您可以在其中找到一个名为idlist.txt的文件,它有两行内容:
PMID:29651880
PMID:29303721
此外,为您提供参考,我已经使用以下浏览器进行了测试,全部通过:
UnhandledPromiseRejectionWarning: Error: blob is not supported by this platform
另外,我如何在同一目录中压缩一个已经存在的文件? - jupiterjellyfiles
可以是一组fetch
响应,例如,尽管有许多支持的输入):import { downloadZip } from "client-zip/index.js"
import FileSaver from "file-saver"
const content = await downloadZip(files).blob()
FileSaver.saveAs(content, "download.zip");
基本上和Yuci的答案用法相同,但已更新至2020年。
像下面这样在您的html文件中导入jszip.js文件
<script type="text/javascript" src="jszip.js"></script>
在您的代码中添加下面的函数并调用它
onClickDownload: function () {
var zip = new JSZip();
for (var i = 0; i < 5; i++) {
var txt = 'hello';
zip.file("file" + i + ".txt", txt);
}
zip.generateAsync({
type: "base64"
}).then(function(content) {
window.location.href = "data:application/zip;base64," + content;
});
}
您可以从我的git存储库下载示例代码,链接在此处(GIT 链接)
var uriContent = URL.createObjectURL(contentBlob);
var lnkDownload = document.getElementById('lnkDownload');
lnkDownload.download = 'MyDownload.zip';
lnkDownload.href = uriContent;
lnkDownload.click();
- tgraupmannZip {
constructor(name) {
this.name = name;
this.zip = new Array();
this.file = new Array();
}
dec2bin=(dec,size)=>dec.toString(2).padStart(size,'0');
str2dec=str=>Array.from(new TextEncoder().encode(str));
str2hex=str=>[...new TextEncoder().encode(str)].map(x=>x.toString(16).padStart(2,'0'));
hex2buf=hex=>new Uint8Array(hex.split(' ').map(x=>parseInt(x,16)));
bin2hex=bin=>(parseInt(bin.slice(8),2).toString(16).padStart(2,'0')+' '+parseInt(bin.slice(0,8),2).toString(16).padStart(2,'0'));
reverse=hex=>{
let hexArray=new Array();
for(let i=0;i<hex.length;i=i+2)hexArray[i]=hex[i]+''+hex[i+1];
return hexArray.filter((a)=>a).reverse().join(' ');
}
crc32=r=>{
for(var a,o=[],c=0;c<256;c++){
a=c;
for(var f=0;f<8;f++)a=1&a?3988292384^a>>>1:a>>>1;
o[c]=a;
}
for(var n=-1,t=0;t<r.length;t++)n=n>>>8^o[255&(n^r[t])];
return this.reverse(((-1^n)>>>0).toString(16).padStart(8,'0'));
}
fecth2zip(filesArray,folder=''){
filesArray.forEach(fileUrl=>{
let resp;
fetch(fileUrl).then(response=>{
resp=response;
return response.arrayBuffer();
}).then(blob=>{
new Response(blob).arrayBuffer().then(buffer=>{
console.log(`File: ${fileUrl} load`);
let uint=[...new Uint8Array(buffer)];
uint.modTime=resp.headers.get('Last-Modified');
uint.fileUrl=`${this.name}/${folder}${fileUrl}`;
this.zip[fileUrl]=uint;
});
});
});
}
str2zip(name,str,folder){
let uint=[...new Uint8Array(this.str2dec(str))];
uint.name=name;
uint.modTime=new Date();
uint.fileUrl=`${this.name}/${folder}${name}`;
this.zip[uint.fileUrl]=uint;
}
files2zip(files,folder){
for(let i=0;i<files.length;i++){
files[i].arrayBuffer().then(data=>{
let uint=[...new Uint8Array(data)];
uint.name=files[i].name;
uint.modTime=files[i].lastModifiedDate;
uint.fileUrl=`${this.name}/${folder}${files[i].name}`;
this.zip[uint.fileUrl]=uint;
});
}
}
makeZip(){
let count=0;
let fileHeader='';
let centralDirectoryFileHeader='';
let directoryInit=0;
let offSetLocalHeader='00 00 00 00';
let zip=this.zip;
for(const name in zip){
let modTime=()=>{
lastMod=new Date(zip[name].modTime);
hour=this.dec2bin(lastMod.getHours(),5);
minutes=this.dec2bin(lastMod.getMinutes(),6);
seconds=this.dec2bin(Math.round(lastMod.getSeconds()/2),5);
year=this.dec2bin(lastMod.getFullYear()-1980,7);
month=this.dec2bin(lastMod.getMonth()+1,4);
day=this.dec2bin(lastMod.getDate(),5);
return this.bin2hex(`${hour}${minutes}${seconds}`)+' '+this.bin2hex(`${year}${month}${day}`);
}
let crc=this.crc32(zip[name]);
let size=this.reverse(parseInt(zip[name].length).toString(16).padStart(8,'0'));
let nameFile=this.str2hex(zip[name].fileUrl).join(' ');
let nameSize=this.reverse(zip[name].fileUrl.length.toString(16).padStart(4,'0'));
let fileHeader=`50 4B 03 04 14 00 00 00 00 00 ${modTime} ${crc} ${size} ${size} ${nameSize} 00 00 ${nameFile}`;
let fileHeaderBuffer=this.hex2buf(fileHeader);
directoryInit=directoryInit+fileHeaderBuffer.length+zip[name].length;
centralDirectoryFileHeader=`${centralDirectoryFileHeader}50 4B 01 02 14 00 14 00 00 00 00 00 ${modTime} ${crc} ${size} ${size} ${nameSize} 00 00 00 00 00 00 01 00 20 00 00 00 ${offSetLocalHeader} ${nameFile} `;
offSetLocalHeader=this.reverse(directoryInit.toString(16).padStart(8,'0'));
this.file.push(fileHeaderBuffer,new Uint8Array(zip[name]));
count++;
}
centralDirectoryFileHeader=centralDirectoryFileHeader.trim();
let entries=this.reverse(count.toString(16).padStart(4,'0'));
let dirSize=this.reverse(centralDirectoryFileHeader.split(' ').length.toString(16).padStart(8,'0'));
let dirInit=this.reverse(directoryInit.toString(16).padStart(8,'0'));
let centralDirectory=`50 4b 05 06 00 00 00 00 ${entries} ${entries} ${dirSize} ${dirInit} 00 00`;
this.file.push(this.hex2buf(centralDirectoryFileHeader),this.hex2buf(centralDirectory));
let a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([...this.file],{type:'application/octet-stream'}));
a.download = `${this.name}.zip`;
a.click();
}
}
接下来,创建一个名为 Zip 的新对象。
z=new Zip('myZipFileName');
filesArray=[
'file01.ext',
'file02.ext',
'file...'
];
z.fecth2zip(filesArray,'public/');
z.str2zip('test.txt','content','public/teste/');
或者上传到zip文件中。
将onchange事件放置在输入文件中,将文件发送到函数files2zip(this.files)。
<input type="file" onchange="z.files2zip(this.files)" value='files' multiple>
将所有对象放入Zip对象文件中后,只需下载该文件。
<input type="button" onclick="z.makeZip()" value='Zip'>
可以在此处找到该类: https://github.com/pwasystem/zip/
var z=new Zip('myZipFileName');
z.str2zip('test.txt','content');
z.makeZip();
- Simon Sawyer这是一个比较旧的问题,但我在搜索创建zip归档文件的解决方案时遇到了它。
对于我的用例,我正在使用node.js从非常大的日志源每分钟创建数千个zip归档文件,每个归档文件最多包含200个文件。
我尝试过JSZip,由于性能问题和不值得追踪的内存泄漏而导致非常糟糕的结果。由于我的用例相当极端,所以它是一次很大的压力测试。
我在这里提到另一个值得其他人检查的纯JavaScript zip库。
最终我使用了fflate。
https://github.com/101arrowz/fflate
这个库表现非常出色。我只使用9级压缩的zip归档功能,但fflate是一个全功能库,可在服务器端使用,并支持完整的浏览器(2011+)。我没有在这里包含任何示例,因为fflate文档非常详细。我强烈推荐它作为替代选择。
示例:将input.txt压缩为input.txt.gz
const zlib = require('zlib');
const fs = require('fs');
const gzip = zlib.createGzip();
const input = fs.createReadStream('input.txt');
const output = fs.createWriteStream('input.txt.gz');
input.pipe(gzip).pipe(output);
步骤1:您需要从node中require
每个本地模块 - require是ES5的一部分。如先前提到的Zlib,以及fs
模块,即文件系统模块。
const zlib = require('zlib');
const fs = require('fs');
步骤二: 使用fs模块,可以创建readstream, 用于读取数据块。此方法返回一个readstream对象;可读流。
const input = fs.createReadStream(FILE PATH HERE);
注意:此读取流对象将再次进行管道传输;对读取流对象进行的这种管道串联可以无限进行,使得管道非常灵活。
ReadStream.pipe(DoesSomething).pipe(SomethingElse).pipe(ConvertToWriteStream)
步骤3:已经被管道处理和压缩的读取流对象接着就会转换成写入流对象。
const output = fs.createWriteStream('input.txt.gz');
input.pipe(gzip).pipe(output); // returned filename input.txt.gz, within local directory
这个库可以让你轻松输入文件路径并决定压缩文件的位置。如果需要,你也可以选择反向操作。
通过新的HTML5文件API和类型化数组,您几乎可以在JavaScript中实现任何想要的功能。然而,浏览器支持并不是很好。我猜这就是你所说的“未解决问题”。我建议暂时在服务器上进行操作。例如,在PHP中,您可以使用此扩展程序。