file-saver + jszip 实现批量读取文件并压缩下载


背景

因项目中有批量下载文件的需求,文件类型包含 jpg/png/pdf/ofd/xml 等多种格式,因下载接口只支持单个文件下载,每个文件下载都需要创建一个 a 标签来实现下载,下载的文件也都是单个分开的,交互不是很友好,博主想到能否实现将下载的文件生成一个压缩包下载到本地,所以找到了以下的解决方案。

一、依赖包的版本及安装

jszip:3.9.1
file-saver:2.0.5

npm i jszip@3.9.1 file-saver@2.0.5

提示:依赖包的版本差异不大,可能引入方式会有变化,若版本不一致具体可参考官方提供的文档

二、封装工具函数

import JSZip from 'jszip'
import FileSaver from 'file-saver'

/**
* 批量下载文件并压缩
* @param {Array} fileIdList 文件资源 id 数组
* @param {String} zipName 压缩包的名称
*/
export async function batchDownloadFile(fileIdList, zipName = '未命名.zip') {
  if (!fileIdList.length) {
  	console.log('选中的数据中不包含文件信息')
  	return
  }
  const jszip = new JSZip()
  let promises = []
  await fileIdList.forEach(fileId => {
    // 调请求获取文件资源
    const promise = $vm.$http.get('http://www.test.com/downloadFile', { fileId }, {
      responseType: 'arraybuffer',
      responseAll: true, // 自定义封装的请求方式,重点是拿到请求的所有响应信息
      headers: { token: '123' }
    }).then(response => {
      const { headers, data } = response
      const fileName = headers['content-disposition'] // 和服务端协定的文件名响应头存放属性名
      jszip.file(fileName, data, { binary: true }) // 对单个下载的文件压缩
    })
    promises.push(promise)
  })
  // 批量调用下载文件请求
  Promise.all(promises).then(() => {
    jszip.generateAsync({ type: 'blob' }).then(content => {
      FileSaver.saveAs(content, zipName)
    })
  })
}

JSZip 的 generateAsync 方法用于生成 ZIP 文件的内容。它接受两个参数:

  1. options:一个对象,用于配置生成的 ZIP 文件。这个对象可以包含以下属性:
  • type:生成的数据类型。可以是 “base64”、“binarystring”、“uint8array”、“arraybuffer”、“blob”、“nodebuffer” 中的一种。默认值是 “base64”

  • compression:压缩算法。可以是 “STORE”(无压缩)或 “DEFLATE”(使用 zlib 进行压缩)。默认值是 “STORE”

  • compressionOptions:一个对象,用于配置压缩算法。对于 “DEFLATE” 压缩,可以包含 level 属性来设置压缩级别。

  • mime:生成的数据的 MIME 类型。默认值是 “application/zip”。

  • platform:生成的 ZIP 文件的平台。可以是 “DOS” 或 “UNIX”。默认值是 “DOS”。

  1. updateCallback:一个函数,会在生成 ZIP 文件的过程中被周期性地调用。这个函数接受一个参数,是一个表示进度的数字(从 0 到 1)。

三、简单的原理介绍

1. jszip

JSZip 是一个 JavaScript 库,用于创建、读取和编辑 .zip 文件。它使用 JavaScript 实现了 ZIP 文件格式的相关规范,可在浏览器和 Node.js 环境中使用。

以下是 JSZip 的一些主要实现原理:

  1. ZIP 文件格式:一个 ZIP 文件包含了一个或多个被压缩的文件,以及描述这些文件的元数据。JSZip 实现了 ZIP 文件格式的相关规范,包括文件的压缩和解压缩、元数据的读取和写入等。

  2. 数据压缩:JSZip 支持多种数据压缩算法,包括 STORE(无压缩)和 DEFLATE。DEFLATE 是一种常用的数据压缩算法,它结合了 LZ77 和 Huffman 编码。JSZip 使用 JavaScript 实现了这些压缩算法。

  3. 数据结构:JSZip 使用 JavaScript 对象来表示 ZIP 文件和其中的文件。每个 JSZip 对象代表一个 ZIP 文件,每个 JSZipObject 对象代表一个文件。你可以使用 JSZip 提供的 API 来操作这些对象,例如添加和删除文件、读取和修改文件内容等。

  4. 异步处理:JSZip 支持异步 API,这意味着你可以在处理大文件或多个文件时避免阻塞主线程。JSZip 使用 Promise 来实现异步处理。

  5. 兼容性:JSZip 可以在多种环境中使用,包括现代浏览器、旧版浏览器和 Node.js。为了实现这种兼容性,JSZip 使用了一些兼容性技术,例如使用 Blob 和 ArrayBuffer 来处理二进制数据、使用 polyfill 来支持旧版浏览器等。

2.file-saver

FileSaver.js 是一个 JavaScript 库,它提供了一个在客户端保存文件的解决方案,无论它是从 JavaScript 生成的数据还是从远程服务器获取的数据。

以下是 FileSaver.js 的一些主要实现原理:

  1. 创建 Blob 对象:FileSaver.js 首先会创建一个 Blob 对象,这个对象包含了要保存的数据。Blob 对象是一个可以存储大量二进制数据的对象,它可以用来表示文件的内容。

  2. 创建 Object URL:然后,FileSaver.js 会使用 URL.createObjectURL 方法创建一个表示 Blob 对象的 Object URL。这个 URL 可以被浏览器识别,并用来下载 Blob 对象的内容。

  3. 创建并点击 a 标签:接着,FileSaver.js 会创建一个 a 标签,设置其 href 属性为 Object URL,设置其 download 属性为要保存的文件名,然后模拟点击这个 a 标签。这会触发浏览器的下载行为,将 Blob 对象的内容保存为一个文件。在不支持 download 属性或者 Blob 对象的浏览器中,FileSaver.js 可能会退化为打开文件而不是下载文件

  4. 回收资源:最后,FileSaver.js 会使用 URL.revokeObjectURL 方法回收 Object URL。这是因为每个 Object URL 都会占用一些内存,当它不再需要时,应该尽快回收。


四、扩展 - FileSaver 模拟实现

/**
 * 下载文件
 * @param {} data 创建 Blob 对象的数据
 * @param {String} filename 文件名
 * @param {String} mime 文件 MIME 类型
*/
export const fileSaveAs = (data, filename, mime) => {
  let blobData = [data]
  let blob = new Blob(blobData, {type: mime || 'application/zip'})
  if (typeof window.navigator.msSaveBlob !== 'undefined') {
    window.navigator.msSaveBlob(blob, filename)
  } else {
    let blobURL = (window.URL && window.URL.createObjectURL) ? window.URL.createObjectURL(blob) : window.webkitURL.createObjectURL(blob)
    let tempLink = document.createElement('a')
    tempLink.style.display = 'none'
    tempLink.href = blobURL
    tempLink.setAttribute('download', filename)
    if (typeof tempLink.download === 'undefined') {
      tempLink.setAttribute('target', '_blank')
    }
    document.body.appendChild(tempLink)
    tempLink.click()
    setTimeout(() => {
      document.body.removeChild(tempLink)
      window.URL.revokeObjectURL(blobURL)
    }, 200)
  }
}
  • FileSaver.saveAs(content, zipName) 可直接替换成 fileSaveAs(content, zipName)
  • 22
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值