前端文件打包压缩下载?

现在有一个批量下载的功能,需要将多个文件下载,如何下载显示进度条,进度条到100下载文件?

阅读 233
avatarAI BotBETA

实现前端批量下载并显示进度条的核心步骤:

  1. 使用JSZip进行文件打包

    import JSZip from 'jszip';
    import { saveAs } from 'file-saver';
    
    const zip = new JSZip();
  2. 进度计算逻辑

    let loaded = 0;
    const totalSize = files.reduce((sum, file) => sum + file.size, 0);
    
    const updateProgress = (chunk) => {
      loaded += chunk;
      const percent = Math.min((loaded / totalSize) * 100, 100);
      progressBar.value = percent.toFixed(2);
    };
  3. 文件下载核心方法

    const downloadFile = async (url, filename) => {
      const response = await axios.get(url, {
     responseType: 'blob',
     onDownloadProgress: (progressEvent) => {
       updateProgress(progressEvent.loaded);
     }
      });
      
      zip.file(filename, response.data);
    };
  4. 批量下载执行

    const downloadAll = async (files) => {
      try {
     await Promise.all(files.map(file => downloadFile(file.url, file.name)));
     
     const content = await zip.generateAsync({ type: 'blob' }, metadata => {
       progressBar.value = 100 * metadata.percent; // 压缩阶段进度
     });
     
     saveAs(content, 'archive.zip');
      } catch (error) {
     console.error('下载失败:', error);
      }
    };

优化建议:

  1. 分阶段进度计算(下载90% + 压缩10%)
  2. 添加并发控制防止浏览器请求过多
  3. 使用Web Worker处理大文件压缩
  4. 添加错误重试机制
  5. 支持文件下载中断恢复

注意事项:

  • 浏览器对Blob大小有限制(通常chrome限制2GB)
  • 大文件建议后端打包
  • 需要处理跨域问题
  • 移动端需要兼容性测试
2 个回答

安装fflatefile-saver插件,分别是创建zip和保存文件。

export const fetchAndZipFiles = async (opts: {
    zipName: string;
    files: Array<{url: string; filename: string}>;
    onSuccess?: () => void;
    onProgress?: (v: number) => void;
    onError?: (error: Error) => void;
}) => {
    const {zipName, files, onProgress, onError, onSuccess} = opts;
    onProgress?.(5);

    const zipFiles: Record<string, Uint8Array> = {};
    const totalFiles = files.length;

    let downloadedFiles = 0;

    try {
        for (const file of files) {
            if (!file.filename) {
                throw new Error('File name is missing');
            }

            const response = await fetch(file.url);

            if (!response.ok) {
                throw new Error(`Failed to fetch ${file.url}: ${response.statusText}`);
            }

            const blob = await response.blob();
            const arrayBuffer = await blob.arrayBuffer();
            zipFiles[file.filename] = new Uint8Array(arrayBuffer);

            downloadedFiles += 1;
            // -- 更新进度以反映基于文件数量的总进度的90%
            onProgress?.(5 + Math.round((downloadedFiles / totalFiles) * 90));
        }

        const zipData = zipSync(zipFiles);
        const zipBlob = new Blob([zipData], {type: 'application/zip'});
        saveAs(zipBlob, `${zipName}.zip`);

        // -- 保存文件后,将进度设置为100%
        onProgress?.(100);
        onSuccess?.();
    } catch (error) {
        onError?.(error);
    }
};

调用方法

    const files = [
        {
            url: 'https://panacro-ctms.oss-cn-huhehaote-nebula-1.aliyuncs.com/panacro-ctms_1741075559535_696.pdf',
            filename: 'a.pdf',
        },
        {
            url: 'https://panacro-ctms.oss-cn-huhehaote-nebula-1.aliyuncs.com/panacro-ctms_1741075559535_696.pdf',
            filename: 'b.pdf',
        }
    ];

    fetchAndZipFiles({
        files,
        zipName: 'files',
        onProgress: (progress) => {
            console.time('timer');
            console.log('progress', progress);
        },
        onError: (error) => {
            console.log(error);
        },
        onSuccess: () => {
            console.log('导出成功');
            console.timeEnd('timer');
        },
    });
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏