adm-zip、archiver、jszip、yazl、zip-lib 和 zip-stream 是 JavaScript 生态中用于处理 ZIP 压缩文件的常用 npm 包。它们各自专注于不同的使用场景:部分库支持 ZIP 文件的创建(压缩),部分支持读取(解压),还有一些同时支持双向操作。这些库在浏览器兼容性、Node.js 流式处理、API 设计和功能完整性方面存在显著差异,适用于前端下载生成、后端文件处理、CLI 工具开发等不同工程需求。
在现代前端开发中,处理 ZIP 文件的需求日益常见 —— 无论是让用户下载打包的资源、上传压缩包解析内容,还是在浏览器中动态生成压缩文件。Node.js 生态提供了多个 ZIP 相关库,但它们的设计目标、能力边界和使用场景差异显著。本文将从工程实践角度,深入剖析 adm-zip、archiver、jszip、yazl、zip-lib 和 zip-stream 的技术特性,帮助你做出精准选型。
首先明确一点:这些库并非都支持“创建”和“解压”双向操作。有些专注压缩(如 yazl),有些专注解压(如 adm-zip),而另一些则是全功能方案(如 jszip)。理解这一点是选型的第一步。
adm-zip:可读取并解压 ZIP 文件(支持内存或文件系统)。jszip:可在浏览器和 Node.js 中加载 ZIP 并提取内容。archiver:通用归档工具,支持 ZIP、TAR 等格式,输出流式数据。jszip:支持在内存中构建 ZIP 并导出为 Blob、Buffer 或 Base64。yazl:纯 ZIP 压缩库,仅支持创建 ZIP,不支持解压。zip-lib:基于 yazl 和 yauzl 封装,提供更简洁的 API,支持压缩和解压。zip-stream:底层 ZIP 流生成器,通常作为 archiver 的依赖,不直接面向应用层。⚠️ 注意:
zip-stream是一个低级流工具,官方文档明确指出它主要用于archiver内部,不建议在应用代码中直接使用。本文仍将其纳入比较,但会明确其定位。
adm-zip:文件系统友好型解压adm-zip 最适合需要直接操作文件系统的场景(如 CLI 工具或后端服务)。它能从文件路径或 Buffer 加载 ZIP,并支持提取到磁盘或读取内存中的条目。
// adm-zip: 从文件解压
const AdmZip = require('adm-zip');
const zip = new AdmZip('./archive.zip');
// 提取所有文件到目录
zip.extractAllTo('./output/');
// 读取单个文件内容(Buffer)
const entry = zip.getEntry('file.txt');
const content = entry.getData(); // Buffer
jszip:浏览器优先的解压jszip 在浏览器中表现优异,支持从 Blob、ArrayBuffer 或 Base64 加载 ZIP,并以 Promise 方式异步读取内容。
// jszip: 浏览器中解压 Blob
import JSZip from 'jszip';
const zip = new JSZip();
const content = await zip.loadAsync(blob); // blob 来自 input[type=file]
// 读取文件内容为文本
const text = await content.file('file.txt').async('text');
zip-lib:简化版双向操作zip-lib 对 yauzl(解压)和 yazl(压缩)做了封装,提供统一的 Promise 接口。
// zip-lib: 解压文件到内存对象
import { unzip } from 'zip-lib';
const files = await unzip('./archive.zip');
// 返回 { [filename]: Buffer } 对象
其他库(
archiver,yazl,zip-stream)不支持解压,此处不提供示例。
archiver:流式、多格式、大文件友好archiver 是最强大的压缩方案,尤其适合处理大文件或需要流式输出的场景(如 HTTP 响应)。它通过管道(pipe)将数据写入可写流(如文件或网络响应)。
// archiver: 流式压缩到文件
const fs = require('fs');
const archiver = require('archiver');
const output = fs.createWriteStream('archive.zip');
const archive = archiver('zip');
archive.pipe(output);
archive.file('file.txt', { name: 'file.txt' });
archive.finalize(); // 触发写入
jszip:内存中构建,适合小文件jszip 将所有内容保留在内存中,适合前端生成小 ZIP 并触发下载。
// jszip: 浏览器中生成 ZIP 并下载
import JSZip from 'jszip';
const zip = new JSZip();
zip.file('hello.txt', 'Hello World!');
const blob = await zip.generateAsync({ type: 'blob' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'archive.zip';
a.click();
yazl:极简 ZIP 创建器yazl 只做一件事:创建 ZIP 流。你需要手动管理流的写入和结束。
// yazl: 手动流控制
const yazl = require('yazl');
const fs = require('fs');
const zipfile = new yazl.ZipFile();
zipfile.addBuffer(Buffer.from('Hello'), 'hello.txt');
const output = fs.createWriteStream('archive.zip');
zipfile.outputStream.pipe(output);
zipfile.end(); // 必须调用 end()
zip-lib:高层封装,简单易用zip-lib 提供了类似 jszip 的简洁 API,但基于流实现,适合 Node.js 场景。
// zip-lib: 压缩目录到 ZIP
import { zip } from 'zip-lib';
await zip('./source-dir', 'archive.zip');
// 自动递归压缩整个目录
zip-stream:底层流,慎用zip-stream 是 archiver 的底层依赖,直接使用需处理更多细节。
// zip-stream: 不推荐直接使用
const ZipStream = require('zip-stream');
const fs = require('fs');
const archive = new ZipStream();
const output = fs.createWriteStream('archive.zip');
archive.pipe(output);
archive.entry('Hello', { name: 'hello.txt' }, () => {
archive.finish();
});
⚠️ 官方未推荐
zip-stream作为独立使用库,建议优先考虑archiver。
| 库 | 浏览器 | Node.js |
|---|---|---|
adm-zip | ❌(依赖 fs) | ✅ |
archiver | ❌(依赖流和文件系统) | ✅ |
jszip | ✅ | ✅(通过 Buffer) |
yazl | ❌(依赖 Node Stream) | ✅ |
zip-lib | ❌(依赖 fs) | ✅ |
zip-stream | ❌(依赖 Node Stream) | ✅ |
关键结论:
jszip。adm-zip 或 zip-lib。archiver(复杂/大文件)、zip-lib(简单目录)或 yazl(极致控制)。adm-zip:同步 API,错误以 throw 形式抛出,需 try/catch。jszip:异步 API(Promise),错误通过 reject 传递。archiver:基于流,需监听 'error' 事件。yazl / zip-stream:流式错误同样需监听 'error'。zip-lib:Promise 封装,错误通过 reject 传递,更符合现代习惯。是否在浏览器中运行?
jszip是否需要解压 ZIP?
adm-zip(需文件系统操作)或 zip-lib(只需内存内容)压缩场景复杂度?
archiverzip-libyazlzip-streamadm-zip:Node.js 文件系统解压首选,API 直观但同步阻塞。archiver:Node.js 压缩王者,功能全面,适合生产级大文件处理。jszip:唯一跨环境(浏览器 + Node.js)的全功能库,前端必备。yazl:轻量 ZIP 创建器,适合定制化流式压缩逻辑。zip-lib:对 yazl/yauzl 的现代化封装,API 简洁,适合快速集成。zip-stream:底层工具,不推荐应用层直接使用。选择 ZIP 库不是追求“最强大”,而是匹配你的运行环境、功能需求和数据规模。希望本文能帮你避开陷阱,直击核心。
选择 adm-zip 如果你需要在 Node.js 环境中直接操作文件系统来解压 ZIP 文件,例如从磁盘读取 ZIP 并提取内容到指定目录。它的 API 简单直观,适合同步处理小型 ZIP 文件,但不支持浏览器环境,且无法创建 ZIP。
选择 archiver 如果你在 Node.js 中需要流式压缩大文件或目录,支持 ZIP、TAR 等多种格式,并计划将输出直接管道到 HTTP 响应或文件流。它是处理复杂归档任务的工业级选择,但不适用于浏览器。
选择 jszip 如果你的应用需要在浏览器中动态生成或解析 ZIP 文件(如用户上传解析或前端打包下载),或者需要跨 Node.js 与浏览器的统一 API。它完全基于内存操作,适合中小型文件,是前端场景的唯一可行方案。
选择 yazl 如果你在 Node.js 中需要精细控制 ZIP 的创建过程(如逐条添加条目并管理底层流),且不需要解压功能。它是一个轻量、专注的 ZIP 生成器,适合构建自定义压缩逻辑,但需手动处理流生命周期。
选择 zip-lib 如果你在 Node.js 中希望用简洁的 Promise API 快速完成目录压缩或 ZIP 解压,而不想处理底层流细节。它封装了 yazl 和 yauzl,提供高层抽象,适合中小型项目快速集成,但不支持浏览器。
避免在新项目中直接使用 zip-stream,因为它是 archiver 的底层依赖,官方未设计为独立应用库。如果你需要流式 ZIP 生成,请优先选择 archiver;只有在深度定制归档逻辑且了解其内部机制时才考虑此包。
ADM-ZIP is a pure JavaScript implementation for zip data compression for NodeJS.
With npm do:
$ npm install adm-zip
Electron file system support described below.
The library allows you to:
There are no other nodeJS libraries that ADM-ZIP is dependent of
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.
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 });
.
.
.