adm-zip vs extract-zip vs node-unzip-2 vs node-zip vs unzipper vs yauzl
Node.js 中 ZIP 文件处理库选型指南
adm-zipextract-zipnode-unzip-2node-zipunzipperyauzl类似的npm包:

Node.js 中 ZIP 文件处理库选型指南

adm-zip、extract-zip、node-unzip-2、node-zip、unzipper 和 yauzl 都是 Node.js 生态中用于处理 ZIP 文件的 npm 包,但它们在功能范围、API 设计和适用场景上有显著差异。部分库专注于 ZIP 文件的解压(如 extract-zip 和 yauzl),部分支持完整的读写操作(如 adm-zip 和 node-zip),还有一些提供了流式处理能力以应对大文件(如 unzipper 和 yauzl)。这些库共同解决了在服务端处理压缩归档文件的常见需求,包括文件提取、内存解析、动态打包等,但开发者需根据具体任务(如是否需要写入、是否处理大文件、是否要求路径安全)选择最合适的工具。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
adm-zip02,178140 kB552 个月前MIT
extract-zip0399-606 年前BSD-2-Clause
node-unzip-2044-217 年前MIT
node-zip0217-1911 年前-
unzipper047356.8 kB902 个月前MIT
yauzl0822110 kB123 个月前MIT

Node.js 中 ZIP 文件处理库深度对比:adm-zip、extract-zip、node-unzip-2、node-zip、unzipper 与 yauzl

在 Node.js 开发中,处理 ZIP 文件是常见需求 —— 无论是解压用户上传的归档、生成下载包,还是解析依赖资源。但面对 adm-zip、extract-zip、node-unzip-2、node-zip、unzipper 和 yauzl 这些库,开发者常陷入选择困境。它们功能重叠却各有侧重,有的擅长写入,有的专注读取;有的简单直接,有的支持流式处理。本文从真实工程场景出发,深入比较这些库的核心能力、API 设计与适用边界。

📦 功能定位:谁做解压?谁做压缩?

首先明确一点:并非所有库都同时支持压缩与解压。这是选型的第一道分水岭。

支持完整读写(压缩 + 解压)

  • adm-zip:提供完整的 ZIP 文件创建、修改和提取能力。
  • node-zip:基于 JSZip 封装,支持内存中的 ZIP 构建与解析。
  • unzipper:虽以“解压”命名,但其实也支持 ZIP 写入(通过 ZipWriter)。

仅支持解压(只读)

  • extract-zip:专为将 ZIP 文件解压到磁盘目录而设计,不支持内存操作或压缩。
  • yauzl:纯只读库,专注于高效、低内存地读取 ZIP 内容,不提供任何写入 API。
  • node-unzip-2:仅支持解压,且主要面向流式处理 ZIP 条目。

⚠️ 注意:node-unzip-2 是 node-unzip 的社区维护分支,原项目已不再活跃。虽然它仍可工作,但在新项目中建议优先评估更现代的替代品。

💾 解压到磁盘:简单任务 vs 精细控制

最常见的需求是“把 ZIP 文件解压到某个文件夹”。此时,extract-zip 是最直接的选择。

// extract-zip: 一行代码解压到目录
const extract = require('extract-zip');

await extract('archive.zip', { dir: './output' });

相比之下,其他库需要更多代码:

// adm-zip: 需要显式调用 extractAllTo
const AdmZip = require('adm-zip');
const zip = new AdmZip('archive.zip');
zip.extractAllTo('./output');

// unzipper: 需要 pipe 到目录流
const unzipper = require('unzipper');
await fs.createReadStream('archive.zip')
  .pipe(unzipper.Extract({ path: './output' }))
  .promise();

// yauzl: 必须手动遍历条目并写入文件
const yauzl = require('yauzl');
yauzl.open('archive.zip', (err, zipfile) => {
  zipfile.on('entry', (entry) => {
    // 手动处理每个 entry,创建目录、写入文件等
  });
});

结论:如果只是简单解压到磁盘,extract-zip 最省事。若需精细控制(如过滤文件、转换内容),则需 unzipper 或 yauzl。

🧠 内存操作:构建 ZIP 或解析内容

当需要在内存中动态生成 ZIP(如打包多个 Buffer)或解析 ZIP 内容而不写入磁盘时,adm-zip 和 node-zip 更合适。

// adm-zip: 添加 Buffer 并获取最终 Buffer
const zip = new AdmZip();
zip.addFile('file.txt', Buffer.from('Hello'));
const buffer = zip.toBuffer();

// node-zip: 基于 JSZip,链式 API
const Zip = require('node-zip');
const zip = new Zip();
zip.file('file.txt', 'Hello');
const buffer = zip.generate({ type: 'nodebuffer' });

而 unzipper 也能读取内存中的 ZIP:

// unzipper: 从 Buffer 解析
const directory = await unzipper.Open.buffer(buffer);
const fileContents = await directory.files[0].buffer();

yauzl 同样支持 Buffer 输入,但需自行管理流:

// yauzl: 从 Buffer 读取
yauzl.fromBuffer(buffer, (err, zipfile) => {
  zipfile.on('entry', (entry) => {
    zipfile.openReadStream(entry, (err, readStream) => {
      // 处理流
    });
  });
});

🌊 流式处理:大文件与低内存场景

处理大型 ZIP 文件时,内存占用是关键。yauzl 和 unzipper 原生支持流式读取,避免一次性加载整个文件。

// yauzl: 流式读取(推荐用于大文件)
const yauzl = require('yauzl');
yauzl.open('large.zip', (err, zipfile) => {
  zipfile.on('entry', (entry) => {
    zipfile.openReadStream(entry, (err, readStream) => {
      readStream.pipe(process.stdout); // 或写入文件
    });
  });
});

// unzipper: 同样支持流
fs.createReadStream('large.zip')
  .pipe(unzipper.Parse())
  .on('entry', (entry) => {
    entry.pipe(process.stdout);
  });

而 adm-zip 和 node-zip 默认将整个 ZIP 加载到内存,不适合大文件:

// adm-zip: 整个文件加载到内存
const zip = new AdmZip('large.zip'); // 可能 OOM

结论:处理 >100MB 的 ZIP 文件时,优先选择 yauzl 或 unzipper。

🔒 安全性与可靠性

ZIP 文件可能包含路径遍历攻击(如 ../../../etc/passwd)。安全的库会自动规范化路径。

  • extract-zip:内置路径校验,防止目录遍历。
  • unzipper:Extract 模式默认启用 forceStream: true 和路径检查。
  • yauzl:不处理路径安全,需开发者自行验证 entry.fileName。
  • adm-zip:extractAllTo() 方法有 overwrite 和 keepOriginalPermission 选项,但路径安全需谨慎处理。
// extract-zip: 自动防御路径遍历
await extract('malicious.zip', { dir: './safe' }); // 即使 ZIP 内含 ../ 也会被限制在 ./safe

因此,在处理不可信来源的 ZIP 时,extract-zip 和 unzipper 更安全。

🛠️ API 设计与易用性

  • adm-zip:面向对象,API 直观,适合快速原型开发。
  • extract-zip:单一用途,API 极简。
  • node-zip:封装 JSZip,熟悉前端 JSZip 的开发者上手快。
  • unzipper:支持 Promise、流、事件,灵活但略复杂。
  • yauzl:底层、回调风格,学习曲线陡峭,但控制力最强。
  • node-unzip-2:流式 API,但文档较少,社区支持弱。

📌 总结:如何选择?

场景推荐库理由
简单解压 ZIP 到磁盘extract-zip一行代码搞定,内置安全防护
内存中构建/修改 ZIPadm-zip 或 node-zip完整读写 API,易于使用
流式处理大 ZIP 文件yauzl 或 unzipper低内存占用,适合生产环境
精细控制 ZIP 条目unzipper支持 Promise、流、事件,功能全面
仅需读取 ZIP 元数据yauzl轻量、高效、无多余依赖
避免使用node-unzip-2社区维护,功能已被 unzipper 覆盖

💡 最终建议

  • 新项目首选 unzipper:它平衡了功能、安全性和现代 API(Promise/流),既能解压到磁盘,也能处理内存和流式场景。
  • 仅解压到磁盘?用 extract-zip:简单任务不必过度设计。
  • 需要写入 ZIP?选 adm-zip:成熟稳定,API 清晰。
  • 极致性能与控制?用 yauzl:但准备好写更多胶水代码。

记住:没有“最好”的库,只有“最合适”当前场景的工具。理解每个库的设计边界,才能在工程中做出稳健选择。

如何选择: adm-zip vs extract-zip vs node-unzip-2 vs node-zip vs unzipper vs yauzl

  • adm-zip:

    选择 adm-zip 如果你需要一个功能完整的 ZIP 库,既能读取也能创建或修改 ZIP 文件,并且偏好面向对象的同步 API。它适合中小型 ZIP 文件的内存操作,例如动态生成包含多个文本或二进制文件的压缩包。但注意它会将整个 ZIP 加载到内存,不适合处理大型文件。

  • extract-zip:

    选择 extract-zip 如果你的唯一需求是将 ZIP 文件安全地解压到指定目录,且不需要任何内存解析或流式处理。它提供了最简单的 API,内置路径遍历防护,非常适合处理用户上传的 ZIP 文件并提取到磁盘的场景。

  • node-unzip-2:

    选择 node-unzip-2 仅当你维护一个已有使用该库的旧项目,且无法轻易迁移。作为 node-unzip 的社区分支,它支持流式解压,但缺乏活跃维护和现代 Promise API。在新项目中应优先考虑 unzipper 或 yauzl。

  • node-zip:

    选择 node-zip 如果你熟悉前端 JSZip 库,并希望在 Node.js 中使用类似的链式 API 来构建或解析内存中的 ZIP 对象。它适合需要与前端共享 ZIP 逻辑的全栈项目,但同样会将整个 ZIP 加载到内存,不适合大文件处理。

  • unzipper:

    选择 unzipper 如果你需要一个现代、灵活且功能全面的 ZIP 库,支持 Promise、流式处理、内存解析和磁盘解压。它既能安全地提取文件,也能通过 ZipWriter 创建 ZIP,适用于大多数生产场景,尤其是需要处理不可信来源 ZIP 或大文件的场合。

  • yauzl:

    选择 yauzl 如果你追求极致的性能和低内存占用,且愿意编写更多底层代码来处理 ZIP 条目。它是纯只读库,专为流式读取大型 ZIP 文件而设计,适合需要精细控制解压过程或仅需读取元数据的高性能应用。

adm-zip的README

ADM-ZIP for NodeJS

ADM-ZIP is a pure JavaScript implementation for zip data compression for NodeJS.

Build Status

Installation

With npm do:

$ npm install adm-zip

Electron file system support described below.

What is it good for?

The library allows you to:

  • decompress zip files directly to disk or in memory buffers
  • compress files and store them to disk in .zip format or in compressed buffers
  • update content of/add new/delete files from an existing .zip

Dependencies

There are no other nodeJS libraries that ADM-ZIP is dependent of

Examples

Basic usage

var AdmZip = require("adm-zip");

// reading archives
var zip = new AdmZip("./my_file.zip");
var password = "1234567890";
var zipEntries = zip.getEntries(); // an array of ZipEntry records - add password parameter if entries are password protected

zipEntries.forEach(function (zipEntry) {
    console.log(zipEntry.toString()); // outputs zip entries information
    if (zipEntry.entryName == "my_file.txt") {
        console.log(zipEntry.getData().toString("utf8"));
    }
});
// outputs the content of some_folder/my_file.txt
console.log(zip.readAsText("some_folder/my_file.txt"));
// extracts the specified file to the specified location
zip.extractEntryTo(/*entry name*/ "some_folder/my_file.txt", /*target path*/ "/home/me/tempfolder", /*maintainEntryPath*/ false, /*overwrite*/ true);
// extracts everything
zip.extractAllTo(/*target path*/ "/home/me/zipcontent/", /*overwrite*/ true);

// creating archives
var zip = new AdmZip();

// add file directly
var content = "inner content of the file";
zip.addFile("test.txt", Buffer.from(content, "utf8"), "entry comment goes here");
// add local file
zip.addLocalFile("/home/me/some_picture.png");
// get everything as a buffer
var willSendthis = zip.toBuffer();
// or write everything to disk
zip.writeZip(/*target file name*/ "/home/me/files.zip");

// ... more examples in the wiki

For more detailed information please check out the wiki.

Electron original-fs

ADM-ZIP has supported electron original-fs for years without any user interractions but it causes problem with bundlers like rollup etc. For continuing support original-fs or any other custom file system module. There is possible specify your module by fs option in ADM-ZIP constructor.

Example:

const AdmZip = require("adm-zip");
const OriginalFs = require("original-fs");

// reading archives
const zip = new AdmZip("./my_file.zip", { fs: OriginalFs });
.
.
.

Security

Please report security vulnerabilities privately. See SECURITY.md.