最近写了个网页版的文件批量处理工具,在本地浏览器端处理完成后只能生成多个下载链接导出文件,比较麻烦,要是能打包文件,一次导出就会方便一些。

一般大多数后端语言都会内置有处理 Zip 文件的库,PHP 有 ZipArchive 库,Node.js 有 zlib 库。浏览器端因为很少会需要处理文件,所以没有浏览器支持直接打包或解压 Zip 文件,要实现浏览器打包或解压文件,只能根据 Zip 的打包算法自己实现。

JSZip 是一个 处理 Zip 文件的库,它可以运行在浏览器端和 Node.js。这里就简单写一下 JSZip 的使用,访问 Zip压缩解压demo 可以直接在浏览器端打包和解压 Zip。

下载

使用 npm 安装:

npm install jszip --save

也可以直接访问 JSZip 官网 https://stuk.github.io/jszip/ 下载文件直接在 HTML 中引入,下载的文件是一个 Zip 文件,解压后在 dist 目录中选择 jszip.jsjszip.min.js 引入。

打包文件

下面创建一个 Zip 包,给 Zip 包添加两个文件,然后导出:

import JSZip from 'jszip';

// 创建 zip
const zip = new JSZip();
// 添加一个文件
zip.file('myBlog.txt', 'https://www.misterma.com');
// 再添加一个文件
zip.file('myGithub.txt', 'https://github.com/changbin1997');
// 生成 Blob 和导出 zip 文件
zip.generateAsync({ type: 'blob' }).then(blob => {
  // 创建一个链接
  const link = document.createElement('a');
  // 将 blob 作为链接的内容
  link.href = URL.createObjectURL(blob);
  // 设置链接的下载名称
  link.download = 'file.zip';
  // 点击链接
  link.click();
}).catch(() => {
  alert('错误');
});

上面使用 new JSZip() 创建了一个 Zip,然后使用 file 方法添加了 myBlog.txtfile 两个文件,然后使用 generateAsync 生成了一个 Blob,这个 Blob 可以使用下载链接导出,也可以使用 FormData 封装上传。

从外部添加打包文件

下面使用 input 文件表单选择文件打包,然后导出。

HTML:

<input type="file" id="file-input" multiple>
<button type="button" id="export-file-btn">导出Zip文件</button>

上面的 HTML 包含一个可以多选的文件表单和一个导出按钮。

JavaScript:

import JSZip from 'jszip';

const fileInput = document.querySelector('#file-input');  // 文件表单
const exportBtn = document.querySelector('#export-file-btn');  // 导出按钮

// 导出按钮点击
exportBtn.addEventListener('click', () => {
  // 如果没有文件就不再往下执行
  if (fileInput.files.length < 1) {
    alert('请选择文件');
    return;
  }
  
  // 创建一个 JSZip 对象
  const zip = new JSZip();
  for (let i = 0; i < fileInput.files.length; i++) {
    // 将文件加入到 JSZip 对象中
    zip.file(fileInput.files[i].name, fileInput.files[i]);
  }

  // 将 JSZip 对象转换为 Blob 对象
  zip.generateAsync({ type: 'blob' }).then((blob) => {
    // 创建一个链接
    const link = document.createElement('a');
    // 将 Blob 对象设置为链接的 href 属性
    link.href = URL.createObjectURL(blob);
    // 将文件名设置为链接的 download 属性
    link.download = 'file.zip';
    // 点击链接
    link.click();
  });
});

JSZip 的 file 方法也能直接添加 FileBlob 文件。

打包文件夹

下面把 myBlog.txt 文件打包到 blog 文件夹,把 myGithub.txt 文件打包到 github 文件夹,然后导出打包完成的 Zip 文件:

JavaScript:

import JSZip from 'jszip';

const zip = new JSZip();
// 添加文件
zip.file('blog/myBlog.txt', 'https://www.misterma.com/');
zip.file('github/myGithub.txt', 'https://github.com/changbin1997');
// 生成 Blob 和导出 zip 文件
zip.generateAsync({ type: 'blob' }).then(zipFile => {
  // 创建链接
  const link = document.createElement('a');
  // 设置链接的下载内容
  link.href = URL.createObjectURL(zipFile);
  // 设置链接的下载文件名
  link.download = 'file.zip';
  // 执行下载
  link.click();
});

添加文件的时候可以包含路径和文件名,打包后的 Zip 包内的文件结构如下:

file.zip
├── blog
│   └── myBlog.txt
└── github
    └── myGithub.txt

读取 Zip 文件列表

下面实现 input 文件表单选择文件,然后把读取的 Zip 文件名显示在页面上:

HTML:

<input type="file" id="file-input" multiple>
<button type="button" id="open-zip-btn">读取Zip文件</button>
<ul id="file-list"></ul>

上面的 ul 用来显示文件列表。

JavaScript:

import JSZip from 'jszip';

const fileInput = document.querySelector('#file-input');  // 文件表单
const openZipBtn = document.querySelector('#open-zip-btn');  // 读取Zip文件按钮
const fileList = document.querySelector('#file-list');  // 文件列表

// 读取Zip文件按钮点击
openZipBtn.addEventListener('click', () => {
  // 没有选择文件就不再往下执行
  if (fileInput.files.length < 1) {
    alert('请选择文件');
    return;
  }

  // 读取文件
  JSZip.loadAsync(fileInput.files[0]).then(zip => {
    zip.forEach((relativePath, zipEntry) => {
      // 创建列表项
      const item = document.createElement('li');
      // 设置列表项的文件名
      item.innerHTML = relativePath;
      // 添加列表项到列表中
      fileList.appendChild(item);
    });
  }).catch(() => {
    alert('读取文件失败');
  });
});

读取成功后调用 forEach 可以获取 Zip 包内的所有文件名和文件数据,第一个接收的 relativePath 是文件名,第二个 zipEntry 是文件数据。

读取文件内容

下面把文件内容读取为 Blob,然后生成下载链接:

HTML 还是和上面一样的,一个 id 为 file-inputinput 文件选择表单,一个 id 为 open-zip-btnbutton 读取文件按钮,一个 ul 文件列表。

JavaScript:

import JSZip from 'jszip';

const fileInput = document.querySelector('#file-input');  // 文件表单
const openZipBtn = document.querySelector('#open-zip-btn');  // 读取Zip文件按钮
const fileList = document.querySelector('#file-list');  // 文件列表

// 读取Zip文件按钮点击
openZipBtn.addEventListener('click', () => {
  // 没有选择文件就不再往下执行
  if (fileInput.files.length < 1) {
    alert('请选择文件');
    return;
  }

  // 读取文件
  JSZip.loadAsync(fileInput.files[0]).then(zip => {
    zip.forEach((relativePath, zipEntry) => {
      // 读取文件内容为 Blob
      zipEntry.async('blob').then(blob => {
        // 创建列表项
        const item = document.createElement('li');
        // 创建下载链接
        const link = document.createElement('a');
        // 设置下载链接内容
        link.href = URL.createObjectURL(blob);
        // 设置下载文件名
        link.download = zipEntry.name;
        link.innerHTML = zipEntry.name;
        // 把下载链接添加到列表
        item.appendChild(link);
        // 把列表项添加到列表
        fileList.appendChild(item);
      }).catch(() => {
        alert('读取文件内容失败');
      });
    });
  }).catch(() => {
    alert('读取文件失败');
  });
});

读取 Zip 后调用文件的 async 可以读取 Zip 内的文件内容,可以读取为 base64textbinarystringarrayuint8arrayarraybufferblobnodebuffer,读取完成后会返回一个 Promise,成功 then 可以接收文件内容。

因为浏览器的执行效率不是太高,不建议在浏览器中处理大文件。

以上就是 JSZip 的基本使用,JSZip 有的 API 只能用于 Node.js,要查看 JSZip 的所有 API 可以访问 https://stuk.github.io/jszip/documentation/api_jszip.html

类似文章: