头图
This article introduces the use of the fs module of Node.js to create zip files, which requires the help of the archiver package.

Backend creates archive

This operation is generally initiated by the front end, as shown in the following figure:

Send the selected file address to the backend, the backend creates an archive file based on the file address, and finally returns the address of the archived file to the frontend to complete the download.

 // zip文件临时目录
const ZIP_TEMPORARY = path.resolve(__dirname, '../../static/zip');

/**
 * 文件归档
 * @param opts 其中opts.targets就是所选文件的地址 type:Array
 */
m.zip = (opts) => {
  return new Promise((resolve, reject) => {
    if (!opts.targets || opts.targets?.length === 0) {
      reject({ success: false, msg: '参数错误' });
    }
    const file_name = `/${new Date().getTime()}.zip`;
    const output = fs.createWriteStream(ZIP_TEMPORARY + file_name);
    const archive = archiver('zip', {
      zlib: { level: 9 }, // Sets the compression level.
    });
    
    // 当所有文件都被打包完成会触发这个事件
    output.on('close', () => {
      console.log(`${archive.pointer()} total bytes`);
      console.log('archiver has been finalized and the output file descriptor has closed.');
      resolve({
        success: true,
        hash: m.encode(ZIP_TEMPORARY + file_name),
      });
    });
    output.on('end', () => {
      console.log('Data has been drained');
    });
    // good practice to catch this error explicitly
    archive.on('error', (err) => {
      throw err;
    });
    // 以管道的形式把文件输出到zip
    archive.pipe(output);
    // archive.directory 这个方法比较重要,它的作用是把子文件夹的文件也全部打包
    opts.targets.forEach(async (item) => {
      const info = fs.lstatSync(item);
      if (info.isDirectory()) {
        archive.directory(item, item.split('/').pop(), null);
      } else {
        archive.file(item, { name: item.split('/').pop() });
      }
    });
    archive.finalize().then();
  });
};

In this way, after the program is executed, a .zip file named according to the timestamp can be generated in the specified directory.

Front-end download

After the above program completes the file packaging, we return the address of the .zip to the front end:

 resolve({
    success: true,
    hash: m.encode(ZIP_TEMPORARY + file_name),
  });

Of course, you can also directly feed the file to the front-end download here, but this will make the packager look less pure.

My approach is to write a separate interface for downloading for the front end to call.

The next article will talk about the problems you may encounter when downloading the front end.

Content-Disposition:attachment did not trigger the browser download popup


来了老弟
508 声望31 粉丝

纸上得来终觉浅,绝知此事要躬行