如何使用JavaScript将文件打包成压缩包(.zip)

2025年3月9日

在现代 Web 开发中,压缩文件是一项常见的需求。用户可能需要将多个文件整合为一个压缩包进行下载,或者通过 Web 应用生成文件并导出为 .zip 文件。这篇博文将为你详细介绍如何在浏览器中使用 JavaScript 实现文件的打包和压缩操作。我们将通过使用流行的 JavaScript 库 JSZip 来完成这项工作,并利用 FileSaver.js 来实现文件下载。

使用前的准备

首先,我们需要安装两个常用的库:

  1. JSZip:这是一个轻量级的 JavaScript 库,用于创建和处理 .zip 文件。
  2. FileSaver.js:这个库提供了一个跨浏览器的方式来触发浏览器下载文件。

你可以通过以下方式在项目中安装这些库:

npm install jszip file-saver

或者使用 CDN 引入(在 HTML 中使用):

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js"></script>

工具函数封装

接下来,我们编写一个封装好的工具函数,用来将多个文件打包成一个 .zip 文件,并触发下载。假设我们要打包一系列图片,可以是原始文件,也可以是经过处理后的文件。

通用的 downloadFilesAsZip 函数

import JSZip from "jszip";
import { saveAs } from "file-saver";

/**
 * 下载多个文件并打包为一个 Zip 文件
 * @param {Array} files - 文件对象数组,每个文件对象包含文件的 URL 和文件名
 * @param {string} zipName - 生成的 Zip 文件名称,默认是 'download.zip'
 */
export const downloadFilesAsZip = async (files, zipName = "download.zip") => {
  // 创建一个新的 JSZip 实例
  const zip = new JSZip();

  // 使用 map 创建一个 Promise 数组来处理每个文件
  const fetchPromises = files.map(async (file) => {
    try {
      // 请求文件资源,这里假设文件是通过 URL 提供的
      const response = await fetch(file.url); // 获取文件资源
      const blob = await response.blob(); // 将响应转换为 Blob 对象

      // 将文件添加到压缩包中,使用传入的文件名
      zip.file(file.name, blob);
    } catch (error) {
      console.error(`Failed to add file: ${file.name}`, error);
    }
  });

  // 等待所有文件的下载并添加到 Zip 中
  await Promise.all(fetchPromises);

  // 生成压缩包内容(blob 类型)
  const content = await zip.generateAsync({ type: "blob" });

  // 使用 FileSaver.js 下载压缩包
  saveAs(content, zipName);
};

代码注释解读

  • 创建 JSZip 实例:const zip = new JSZip(); — 创建一个新的 Zip 文件实例,所有的文件将会被添加到这个实例中。
  • 文件下载和打包:使用 fetch() 函数从文件 URL 获取文件的内容,然后将它转换为 blob 格式。这是因为 JSZip 支持通过 blob 格式处理文件。
  • 生成 .zip 文件:通过 zip.generateAsync({ type: "blob" }) 将所有添加到 zip 对象中的文件压缩为一个 .zip 文件,返回一个 blob 对象。
  • 保存文件:通过 saveAs(content, zipName) 使用 FileSaver.js 触发文件下载,content 是生成的压缩包,zipName 是下载的文件名。

如何使用这个工具函数

假设我们有一组图片 URL,并希望将它们打包成一个 .zip 文件进行下载,以下是如何调用 downloadFilesAsZip 函数的示例:

// 示例文件数据:包含文件 URL 和文件名
const files = [
  { url: "https://example.com/image1.jpg", name: "image1.jpg" },
  { url: "https://example.com/image2.jpg", name: "image2.jpg" },
  { url: "https://example.com/image3.jpg", name: "image3.jpg" },
];

// 调用函数下载文件并打包成 zip 文件
downloadFilesAsZip(files, "images.zip");

在这个例子中,我们提供了一个包含图片 URL 和文件名的对象数组。调用 downloadFilesAsZip 函数后,浏览器会自动触发下载操作,并将这些图片打包为一个名为 images.zip 的压缩文件。

常见问题与解决

  1. 跨域问题 如果文件来自不同的域名,确保服务器设置了正确的跨域(CORS)头信息。否则,浏览器会阻止 fetch() 请求,导致文件无法下载。
  2. 大文件下载 如果下载的文件很大,可能需要优化下载流程,例如分块下载或显示进度条等。
  3. 浏览器支持 这个方法依赖于 fetch()FileSaver.js,因此需要支持这些 API 的现代浏览器。如果需要支持旧版浏览器,可以考虑使用 polyfill。

其他方案

除了使用 JSZipFileSaver.js,还有其他几种常见的方案可以实现浏览器端文件压缩和打包:

  1. Pako.jsPako 是一个用于 JavaScript 的 zlib 压缩库,支持 gzip 和 deflate 格式。适合用于较小文件的压缩,且使用较为简单。
  2. Archiver.jsArchiver.js 是一个功能丰富的库,支持压缩为 .tar.zip 等格式,可以在浏览器端进行文件压缩,并提供了更多的控制选项。
  3. zip.jszip.js 是一个支持流式解压和压缩的 JavaScript 库,可以处理较大文件,并提供了压缩到 .zip 文件的功能。
  4. BrowserFS + zip-libBrowserFS 是一个在浏览器中提供文件系统模拟的库,结合 zip-lib 可以创建和下载 .zip 文件,适合需要模拟文件系统的应用。