3

前端批量获取文件并打包压缩解决方案

 2 years ago
source link: https://segmentfault.com/a/1190000040180383
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前端批量获取文件并打包压缩解决方案

前端文件下载我相信很多小伙伴并不陌生,下载文件的形式也有很多,例如,后端返回一个文件地址,我们把地址放在<a></a>标签里面点击下载;或者是通过后端接口返回文件流,我们再对流进行一系列的操作等等。

单个件下载的解决方法有很多,但是当我们需要批量下载文件的时候,我们该怎么去做呢?

面对这样的需求,我们提出了以下几个方案:

方案一:直接获取后端返回文件地址数组,然后一个一个的去下载。但是这样每次下载一个文件,浏览器会显示比较多的下载任务;

方案二:后端对先对文件进行打包压缩处理,然后前端只需要下载一个压缩文件,但是这样会对服务器性能造成很大的影响;

方案三:还是直接获取后端返回的文件地址数组,一个一个的去下载,然后前端来进行打包压缩的处理。

说实话,当时提到前端来打包压缩时,我心中就和一部分小伙伴一样,前端怎么打包压缩?下面这两个优秀的库就可以很好的解决我们的问题。

这里提一下,下面是以React环境下为例,但是在其他环境的思路和用法其实都是大同小异,都可以以下面的内容为参考。

JSZip和FileSaver.js

本节会简单的介绍一下JSZip和FileSaver.js的API和用法。

npm install jszip file-saver

JSZip

JSZip是一个用于创建、读取和编辑.zip文件的javascript库,并且拥有有友好而简单的API。

一个简单的例子

首先我们来实现一个简单的例子,来感受一下这个十分好用的工具

import React , { useState } from 'react';
import JSZip from 'jszip';
import FileSaver from 'file-saver'; 


const MyButton = () => {

    const downloadFile = () => {
        const zip = new JSZip();
        zip.file("Hello.txt", "Hello World\n");
        zip.generateAsync({type:"blob"})
        .then((content) => { 
            FileSaver(content, "example.zip");
        });
    }

    return (
        <div>
            <button onClick={() => {
                downloadFile()
            }}>下载</button>
        </div>
    )
} 

export default MyButton

点击下载按钮,我们就可以得到一个名为example.zip的压缩文件,打开压缩文件,里面也会有一个名为Hello.txt的文件.

简单介绍一下几个API。

创建JSZip实例:

const zip = new JSZip();

创建文件:

zip.file("hello.txt", "Hello World\n");

创建文件夹:

zip.folder("file")

同时创建文件夹和文件:

zip.file("file/hello.txt", "Hello World\n");
// 等同于
zip.folder("file").file("hello.txt", "Hello World\n");

生成一个压缩文件:

我们可以通过.generateAsync(options) 或者 .generateNodeStream(options) 来生成一个压缩文件:

let promise = null;
if (JSZip.support.uint8array) {
  promise = zip.generateAsync({type : "uint8array"});
} else {
  promise = zip.generateAsync({type : "string"});
}

详细API点击官方文档

FileSaver.js

在前面的这个例子中我们运用了JSZip外还使用了FileSaver.js这个库。FileSaver.js是在客户端保存文件的解决方案,非常适合在客户端生成文件。

在上一节的例子中,我们就是通过FileSaver.js把我们生成的.zip文件保存了下来。

FileSaver saveAs(Blob/File/Url, optional DOMString filename, optional Object { autoBom })
import FileSaver from 'file-saver';

const blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
FileSaver.saveAs(blob, "hello world.txt");

更多用法点击官方文档

批量获取文件并打包下载

这两个库我们已经有所了解接下来就是实现我们的需求。这里分两步进行,第一步是获取文件;第二步是打包压缩。

需要操作的源文件地址

这里的文件地址只是一个简单的示例,实际开发的时候视情况而定。

const data = [
    {
        fileUrl: 'https://www.xxx.com/data/data_service/20210429/144b4b1e4e457485c10fed54b8bc8d48.docx',
        fileName: '文件一'
    },
    {
        fileUrl: 'https://www.xxx.com/data/data_service/20210429/144b4b1e4e457485c10fed54b8bc8d48.docx',
        fileName: '文件二'
    },
    {
        fileUrl: 'https://www.xxx.com/data/data_service/20210429/144b4b1e4e457485c10fed54b8bc8d48.docx',
        fileName: '文件三'
    },
    {
        fileUrl: 'https://www.xxx.com/data/data_service/20210429/144b4b1e4e457485c10fed54b8bc8d48.docx',
        fileName: '文件四'
    },
];  
import JSZip from 'jszip';
import FileSaver from 'file-saver';
import requestFile from './requestFile'; //这里是封装的请求函数,大家用自己封装的或者Axios都行

const getFile = (url: string) => {
  return new Promise((resolve, reject) => {
    requestFile(url, {
      method: 'GET',
      responseType: 'blob'
    }).then((res:any) => {
      resolve(res)
    }).catch((error: any) => {
      reject(error)
    })
  })
}

打包压缩下载

这里主要是通过遍历地址数组,然后通过地址从后端获取文件,再进行一个批量压缩打包文件的操作,最后把压缩好的文件保存下来。

/**
 * 打包压缩下载
 * @param data  源文件数组
 * @param fileName  压缩文件的名称
 */
const compressAndDownload = (data: any[], fileName ?: string) => {
  const zip = new JSZip();
  const promises: any[] = [];  //用于存储多个promise
  data.forEach((item: any) => {
    const promise = getFile(item.fileUrl).then((res: any) => {
      const fileName = item.fileName
      zip.file(fileName, res ,{binary: true});
    })
    promises.push(promise)
  })

  Promise.all(promises).then(() => {
    zip.generateAsync({
      type: "blob",
      compression: "DEFLATE",  // STORE:默认不压缩 DEFLATE:需要压缩
      compressionOptions: {
        level: 9               // 压缩等级1~9    1压缩速度最快,9最优压缩方式
      }
    }).then((res: any) => {
      FileSaver.saveAs(res, fileName ? fileName : "压缩包.zip") // 利用file-saver保存文件
    })
  })
}

export default compressAndDownload;

https://stuk.github.io/jszip/

https://github.com/eligrey/Fi...

通过利用JSZip和FileSaver.js,我们可以对后端的批量文件进行一个整合打包压缩,这样既在一定程度上减少了对服务器的压力,在另一方面给人们的感觉就是下载了一个文件,不会一次性弹出很多的下载任务,也在一定程度上提高了体验。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK