前端批量打包下载文件

      最近有个需求需要前端批量打包文件的需求,然后经过搜索,使用到了 jszip 和 file-saver 这两个 js 插件。

      jszip 压缩插件,这个插件用起来个人觉得还算比较容易,官方文档下,仅仅需要几行代码便可以导出一个压缩包文件。

官方示例代码如下,写了简单的注释:

var zip = new JSZip();                           // 初始化jszip对象
zip.file("Hello.txt", "Hello World\n");          // 添加一个 hello.txt 文件,内容为 Hello World
var img = zip.folder("images");                  // 生成一个 images 文件夹
img.file("smile.gif", imgData, {base64: true});  // 在 images 文件夹中加入一个 smile.gif 文件,内容为 base64,options 中 base64 要设置为 true

// 这里接下来是将文件流同步生成压缩文件,并使用 file-saver 保存导出
zip.generateAsync({type:"blob"}).then(function(content) {
    // see FileSaver.js
    saveAs(content, "example.zip");
});

在业务代码里面,由于有多个文件,所以我的代码里面写了的是循环遍历的的,具体代码如下: 

<template>
    <div>
      <p>只要有一个文件下载失败,就停止下载</p>
      <button @click="download(1)" >点击下载</button>
  
      <br />
      <p>忽略在下载失败文件,可以继续下载</p>
      <button @click="download(2)" >点击下载</button>
  
    </div>
  </template>
  <script>
  export default {
    name: 'BatchDownload',
    data () {
      return {
  
      }
    },
    methods: {
      // 只要有一个失败,那就就停止下载
      async downloadAll1 (files, filename) {
        let zip = new JsZip()
        let isFault = false
        for (let i = 0; i < files.length; i++) {
          let folder = files[i]
          let newFolder = zip.folder(folder.folderName)
          
          await new Promise((resolve, reject) => {
  
            return folder.files.reduce((accumulator, item, index) => {
              return accumulator.then(() => fetch(item.url).then(resp => {
                if (resp.status !== 200) {
                  reject(` ${folder.folderName} 的日志文件 ${item.name} 下载失败,已停止下载`)
                } else {
                  return resp.blob()
                }
              }).then(blob => {
                newFolder.file(item.name, blob)
                if (index === folder.files.length - 1) {
                  resolve()
                }
              }))
            }, Promise.resolve())
          }).catch(err => {
            this.$alert(err, '错误', {
              confirmButtonText: '确定',
              type: 'warning'
            })
            isFault = true
          })
  
          if (isFault) {
            break
          }
        }
        if (!isFault) {
          zip.generateAsync({type: "blob"}).then(content => {
            saveAs(content, `${filename}.zip`)
          })
        }
      },
      // 全部下载,失败了那就再文件名后面加上‘下载失败’
      async downloadAll2 (files, filename) {
        let zip = new JsZip()
        let failedFiles = []          // 下载失败文件
        let filesCount = 0            // 总文件
        for (let i = 0; i < files.length; i++) {
          let folder = files[i]
          let newFolder = zip.folder(folder.vin)
          
          await new Promise((resolve, reject) => {

            return folder.files.reduce((accumulator, item, index) => {
              filesCount++
              return accumulator.then(() => fetch(item.url).then(resp => {
                if (resp.status !== 200) {
                  reject(`${folder.vin}/${item.name}`)
                } else {
                  return resp.blob()
                }
              }).then(blob => {
                if (!blob) {
                  newFolder.file(`${item.name}.下载失败`, blob)
                } else {
                  newFolder.file(item.name, blob)
                }
                if (index === folder.files.length - 1) {
                  resolve()
                }
              }))
            }, Promise.resolve())
          }).catch(err => {
            failedFiles.push(err)
          })

        }

        // 下载后提示文案
        let htmlString = `<div>下载成功${filesCount - failedFiles.length}个文件,下载失败${failedFiles.length}个</div>`
        if (failedFiles.length > 0) {
          let filesHtmlString = '<div>失败文件列表如下:</div>'
          failedFiles.forEach(ele => {
            filesHtmlString += `<p>${ele}</p>`
          })
          htmlString += filesHtmlString
        }
        this.$alert(htmlString, '提示', {
          confirmButtonText: '确定',
          type: failedFiles.length > 0 ? 'warning' : 'success',
          dangerouslyUseHTMLString: true
        })
        zip.generateAsync({type: "blob"}).then(content => {
          saveAs(content, `${filename}.zip`)
        })
      },
      download(s) {
        let files = [
          {
            folderName: '123456',
            files: [
              {name: 'a.svg', url: 'http://localhost:8080/img/beian-icon.png'},
              {name: 'b.svg', url: 'http://localhost:8080/img/beian-icon.png'}
            ]
          },
          {
            folderName: '7890',
            files: [
              {name: 'c.svg', url: 'http://localhost:8080/img/beian-icon.png'},
              {name: 'd.svg', url: 'http://localhost:8080/img/beian-icon.png'}
            ]
          }
        ]
  
        if (s === 1) {
  
          this.downloadAll1(files, '文件集合')
        } else {
          downloadAll2(files, '文件集合')
        }
      },
    }
  }
  </script>
  <style lang="scss" scoped>
    
  </style>

       但是 ,在使用过程中发现了一些问题,比如我通过 ajax 请求下来文件,大小大概是 100MB 左右,但是 zip.file() 方法添加进去了,但是文件内容是报错的,导出的是空文件,我估计是浏览器限制或者浏览器内存限制了,希望有用到这个插件的朋友也说说使用体验。

        再说一下,这个需求由于前端打包失败了,后面改成了直接下载好几个文件的那种办法,不过还是用 ajax 请求文件流,方便修改下载文件的名字。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值