跳到主要内容

JSZip 压缩解压文件

JSZip 是一个非常优秀的库的,我们可以在前端实现文件的压缩,以及解压功能。

备注

@zip.js 也是一个十分优秀且全面的库,它支持了更多的功能,但是相对于 JSZip 来说,它的使用难度更大一些,这里我们不做过多的介绍。(其实就是文档中懒得再补充了)

zip.js 是一个用于压缩和解压缩 zip 文件的 JavaScript 开源库(BSD-3-Clause 许可证)。它被设计用来处理大量数据。它特别支持多核压缩、压缩流本机压缩、使用 Zip64 的大于 4GB 的存档、分割 zip 文件和数据加密

一些函数的使用可以参考涛之雨的脚本1脚本2

如何使用

JSZip 的一个新建的实例代表一组文件,可以添加、删除、修改。

我们可以导入现有的 zip 文件,或生成一个新的 zip 文件

获取对象

在引入 js 文件后

创建一个 JSZip 实例

var zip = new JSZip();

函数使用

  • 文件和文件夹的更新

    file 函数以及 folder 函数处理后依然会返回 zip 实例,以供我们进行链式调用。

    // 创建一个文件
    zip.file("hello.txt", "Hello[p my)6cxsw2q");
    // 支持换行符
    zip.file("hello.txt", "Hello World\n");
    // 创建一个文件以及目录
    zip.file("nested/hello.txt", "Hello World\n");
    // 创建一个目录然后创建一个文件
    zip.folder("nested").file("hello.txt", "Hello World\n");

    使用 folder 函数后,返回的对象为创建目录的根,如果在此对象上进行添加文件的操作

    则将他们放入了创建创建的子文件夹目录之中,这只是一个相对路径的对象,添加的文件

    也同样会存在于我们的 zip 实例对象中

    var photoZip = zip.folder("photos");
    // 相当于创建了photos/README
    photoZip.file("README", "a folder with photos");
  • 读取文件

    使用 file 访问文件的内容

    zip
    .file("hello.txt")
    .async("string")
    .then(function (data) {
    // data is "Hello World\n"
    });

    //字符作为一个无符号八位整形的数组
    if (JSZip.support.uint8array) {
    zip
    .file("hello.txt")
    .async("uint8array")
    .then(function (data) {
    // data is Uint8Array { 0=72, 1=101, 2=108, more...}
    });
    }
  • 删除文件

    你可以使用如下命令删除文件或文件夹

    zip.remove("photos/README");
    zip.remove("photos");
    // same as
    zip.remove("photos"); // by removing the folder, you also remove its content.
  • 生成 zip 文件

    使用generateAsync(options),你可以生成一个 zip 文件

    注意,不是一个真正的文件,他仅在内存中表示

    var promise = null;
    if (JSZip.support.uint8array) {
    promise = zip.generateAsync({ type: "uint8array" });
    } else {
    promise = zip.generateAsync({ type: "string" });
    }
  • 加载 Zip 文件

    通过 loadAsync(data)你可以加载一个 zip 文件

    注意,必须使用二进制下载文件然后进行解压

    var new_zip = new JSZip();
    // more files !
    new_zip.loadAsync(content).then(function (zip) {
    // you now have every files contained in the loaded zip
    zip.file("hello.txt").async("string"); // a promise of "Hello World\n"
    });

JSZip 的局限性

  • 不支持加密 zip,分卷 zip 等
  • 可以加载 zip64 文件但不能较大
  • 仅支持 UTF8 编码
  • 读取后再生成 zip, 文件不相同

实战练习

首先我们引入 jszip

// @require      https://cdn.staticfile.org/jszip/3.5.0/jszip.min.js

这里我想读取一个 zip 压缩文件,然后再输出一个 zip 压缩文件,所以我们声明两个 zip

var inZip = new JSZip();
var outZip = new JSZip();

因为文件目标不太好找,所以我在 github 挂了一个美女图片

地址是 https://raw.githubusercontent.com/lihengdao666/Modify-Tampermonkey-Libs/master/testfile/1.zip

提示

githubusercontent 的服务器因为不可抗拒的原因,在大陆可能会出现无法下载的情况,尽可能使用“良好”的网络访问。

首先我们下载文件

GM_xmlhttpRequest({
url: "https://raw.githubusercontent.com/lihengdao666/Modify-Tampermonkey-Libs/master/testfile/1.zip",
responseType: "arraybuffer",
method: "GET",
headers: {},
onload: function (xhr) {
console.log("我下载了");
},
});

这里注意 reponseTypearraybuffer 类型,也就是二进制下载,否则会解压错误

然后我们写解压代码

inZip
.loadAsync(xhr.response)
.then(function (zip) {
console.log("zip", zip);
})
.catch((val) => {
alert("文件下载或解压错误");
});

使用 zip.loadAsync 读取文件,传入一个二进制数据,返回一个 promise

我们对其挂载 thencatch,如果异常就提示文件下载或解压过程错误。

如果解压成功了,就输出 zip 对象,看看到底是什么。

1

这里看到 files 里有一个 2675xxx.jpg 文件,我们试着读取这个文件。

inZip
.file("26758f43cbc6b95fb7b534e5a59006b9.jpg")
.async("blob") // 将其读取为blob类型,返回一个promise,挂上一个then获取写出的blob数据
.then(function (data) {
console.log("data", data);
// 我们创建了一个img的dom对象
// 然后将URL.createObjectURL将一个blob对象转化出来一个地址
// 然后设置给img的src属性
// 并添加到了body上
let img = document.createElement("img");
img.src = URL.createObjectURL(data);
window.document.body.append(img);
// 最后也将其写入到outZip里
outZip.file("test/blob.img", data);
});

可以看到页尾已经显示了图片

2

我们解压文件的时候使用了 zip.file("26758f43cbc6b95fb7b534e5a59006b9.jpg").async("blob")

async 内到底有几种类型?关于这个我们可以查阅文档

看到如下所述的类型

数据类型描述说明
base64将结果转换为一个字符串,以 base64 形式表示二进制数据。将二进制转化为 base64 字符串
text (或 string)将结果转换为一个 Unicode 字符串。返回一个解码的字符串
binarystring将结果转换为一个“二进制”形式的字符串,每个字符使用 1 字节( 2 字节)。返回一个结果为二进制数据的字符串
array将结果转换为一个字节的数组( 0255 之间的数字)。结果将是 bytes 的数组形式
uint8array将结果转换为一个 Uint8Array。需要兼容的浏览器。结果将是无符号 8 位整数的数组形式,需要浏览器兼容
arraybuffer将结果转换为一个 ArrayBuffer。需要兼容的浏览器。结果将是一个二进制类型,需要浏览器兼容
blob将结果转换为一个 Blob。需要兼容的浏览器。结果将是一个 blob 类型,即一个 js 的文件对象
nodebuffer将结果转换为一个 Node.js Buffer。需要 Node.js 环境。结果是一个 nodejsbuffer 类型,需要 nodejs,这里我们是浏览器环境,无需在意

通常我们需要的可能也就是 blobtext 以及 arraybuffer,所以我们着重这几个就可以了

我们刚才已经运行了 outZip.file("test/blob.jpg", data);,因此已经写出了一个文件,所以这里我们可以尝试一下,多写出一些文件看看。

这里为了方便,我们直接嵌套了

inZip
.file("26758f43cbc6b95fb7b534e5a59006b9.jpg")
.async("arraybuffer")
.then(function (data) {
console.log("arraybuffer", data);
outZip.file("test/arraybuffer.jpg", data);
inZip
.file("26758f43cbc6b95fb7b534e5a59006b9.jpg")
.async("uint8array")
.then(function (data) {
console.log("uint8array", data);
outZip.file("test/uint8array.jpg", data);
outZip.generateAsync({ type: "blob" }).then((res) => {
console.log("out", res);
saveAs(res, "美女.zip");
});
});
});

我们把图片读取成 arraybuffer 格式,写出了一个 arraybuffer 的文件,同时将图片读取为 unit8array 格式,并写出一个 unit8array 的文件

最后通过 generteAsync,写出一个文件,并通过 FileSaversaveAs 写出

因为 FileSaver 支持的是 blob,所以我们也要用 generateAsync 函数生成 blob 对象的输出

我们再尝试一下,可以看到下载了文件

3

这三个文件都是可以照常打开的

类型问题

为什么 jszip 支持了这么多类型?

因为有时可能不仅仅是图片,文字,还可能是一些自己构建的格式,或者我们想将一些本地客户端无痛切到网页上做某些特定的操作。

这时候我们可能需要将压缩包的数据解读成不同的格式,实际压缩包的文件只是一堆 01

我们一厢情愿的将其解析成不同的格式,变成文本,图片,二进制,数组,base64编码等

当我们操作之后

可以将其还原为原先的一堆 01

我们要做的就是根据我们想要读取的文件选择相应的格式并且完成我们的需求即可

官方帮助文档

地址 : https://stuk.github.io/jszip/documentation/api_jszip.html