6

Preface

<a></a> download files. For example, the back-end returns a file address, we put the address in the 060c9542c6d0c1 label and click to download; or return the file stream through the back-end interface, we Then perform a series of operations on the stream and so on.

There are many solutions for single download, but when we need to download files in batches, what should we do?

Program

Faced with such demands, we have proposed the following solutions:

program one : directly obtain the back-end return file address array, and then download them one by one. But every time a file is downloaded in this way, the browser will display more download tasks;

program two : the back-end packs and compresses the file first, and then the front-end only needs to download a compressed file, but this will have a great impact on server performance;

plan three : Or directly obtain the file address array returned by the back end, download them one by one, and then the front end will process the packaging and compression.

To be honest, when it was mentioned that the front-end was packaged and compressed, I was like some of my friends in my mind. How to package and compress the front-end? The following two excellent libraries can solve our problem very well.

To mention here, the following is an example in the React environment, but the ideas and usage in other environments are actually similar, and you can use the following as a reference.

JSZip and FileSaver.js

This section will briefly introduce the API and usage of JSZip and FileSaver.js.

installation

npm install jszip file-saver

JSZip

JSZip is a javascript library for creating, reading and editing .zip files, and has a friendly and simple API.

A simple example

First, let’s implement a simple example to get a feel for this very useful tool

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

Click the download button, we can get a example.zip , open the compressed file, there will be a file named Hello.txt inside.

API

Briefly introduce a few APIs.

Create an instance of JSZip:

const zip = new JSZip();

Create a file:

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

Create a folder:

zip.folder("file")

Create folders and files at the same time:

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

Generate a compressed file:

We can generate a compressed file .generateAsync(options) or .generateNodeStream(options)

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

Detailed API click official document

FileSaver.js

In the previous example, we used JSZip and FileSaver.js library. FileSaver.js is a solution for saving files on the client side, which is very suitable for generating files on the client side.

In the example in the previous section, we saved the .zip

grammar

FileSaver saveAs(Blob/File/Url, optional DOMString filename, optional Object { autoBom })

example

import FileSaver from 'file-saver';

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

For more usage, click official document

Get files in batches and package them for download

We have already understood these two libraries. The next step is to achieve our needs. There are two steps here, the first step is to get the file; the second step is to pack and compress.

The address of the source file to be operated

The file address here is just a simple example, it depends on the actual development.

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: '文件四'
    },
];  

Get files

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)
    })
  })
}

Pack and compress download

This is mainly by traversing the address array, and then obtaining the file from the backend through the address, and then performing a batch compression and packaging file operation, and finally saving the compressed file.

/**
 * 打包压缩下载
 * @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;

reference

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

https://github.com/eligrey/FileSaver.js

At last

By using JSZip and FileSaver.js, we can perform an integrated package compression on the back-end batch files, which not only reduces the pressure on the server to a certain extent, but also gives people the feeling that a file is downloaded without Many download tasks pop up at once, which also improves the experience to a certain extent.


xmanlin
1.4k 声望43 粉丝