这些库都用于创建和解压 ZIP 归档文件,但设计目标不同。jszip 是纯 JavaScript 实现,同时支持浏览器和 Node.js,主打异步 API。adm-zip 专注 Node.js 环境,提供同步文件系统操作。zip-stream 专为 Node.js 流式管道设计,适合处理大文件。node-zip 已不再维护,属于遗留方案。
在 JavaScript 项目中处理 ZIP 文件时,开发者常面临选型困难。adm-zip、jszip、node-zip 和 zip-stream 都能完成压缩任务,但它们在运行环境、API 设计和内存管理上差异巨大。本文将从工程实践角度对比它们的核心区别。
运行环境是选型的第一道门槛。有些库依赖 Node.js 特有的文件系统模块,无法在浏览器运行。
jszip 是纯 JavaScript 实现,不依赖任何原生模块。
// jszip: 浏览器或 Node.js 通用
const JSZip = require("jszip");
const zip = new JSZip();
zip.file("hello.txt", "Hello World");
// 生成文件
zip.generateAsync({type:"blob"}).then(function(content) {
// 在浏览器可触发下载
});
adm-zip 依赖 Node.js 的 fs 模块。
// adm-zip: 仅 Node.js
const AdmZip = require("adm-zip");
const zip = new AdmZip();
zip.addFile("hello.txt", Buffer.from("Hello World"));
// 写入本地磁盘
zip.writeZip("output.zip");
zip-stream 同样依赖 Node.js 流模块。
// zip-stream: 仅 Node.js
const ZipStream = require("zip-stream");
const output = require("fs").createWriteStream("output.zip");
const archive = new ZipStream();
archive.pipe(output);
archive.file("hello.txt", { name: "hello.txt" });
archive.finalize();
node-zip 设计初衷是 Node.js 环境。
// node-zip: 仅 Node.js (遗留)
const Zip = require("node-zip");
const zip = new Zip();
zip.file("hello.txt", "Hello World");
// 生成二进制数据
const data = zip.generate({type:"nodebuffer"});
API 的设计决定了代码的编写方式和复杂度。
jszip 使用 Promise 异步 API。
// jszip: 异步 Promise
async function createZip() {
const zip = new JSZip();
zip.file("file.txt", "content");
// 等待生成完成
const content = await zip.generateAsync({type:"nodebuffer"});
return content;
}
adm-zip 主要是同步 API。
// adm-zip: 同步操作
const zip = new AdmZip();
zip.addLocalFile("./input.txt");
// 立即执行写入,阻塞直到完成
zip.writeZip("./output.zip");
console.log("Done");
zip-stream 使用流式 API。
pipe 连接。// zip-stream: 流式管道
const archive = new ZipStream();
archive.pipe(process.stdout);
// 添加文件流
archive.file(fs.createReadStream("./largefile.dat"), {name:"data.dat"});
archive.finalize();
node-zip 使用回调或同步混合。
// node-zip: 旧式 API
const zip = new Zip();
zip.file("file.txt", "content");
// 生成数据,无 Promise 支持
const buffer = zip.generate({type:"nodebuffer"});
处理大文件时,内存占用是关键指标。
jszip 默认将文件加载到内存。
// jszip: 内存占用较高
// 所有文件内容先存入内存对象
zip.file("large.bin", largeBuffer);
// 生成时再次遍历内存
const output = await zip.generateAsync({type:"nodebuffer"});
adm-zip 同样基于内存操作。
// adm-zip: 内存加载
// addLocalFile 会读取文件内容到内存
zip.addLocalFile("./huge_file.iso");
// 写入时一次性写出
zip.writeZip("./archive.zip");
zip-stream 专为低内存设计。
// zip-stream: 流式处理
// 文件内容不一次性加载,而是通过流管道
archive.file(fs.createReadStream("./huge_file.iso"), {name:"data.iso"});
// 内存中只保留当前压缩块
archive.finalize();
node-zip 内存机制不透明。
jszip 早期版本,容易占用高内存。// node-zip: 内存风险
// 生成过程可能占用大量内存
const data = zip.generate({type:"nodebuffer"});
选择开源库必须考虑长期维护情况。
jszip 维护活跃。
adm-zip 维护稳定。
zip-stream 维护良好。
archiver 的核心依赖,更新及时。node-zip 已弃用。
| 特性 | jszip | adm-zip | zip-stream | node-zip |
|---|---|---|---|---|
| 运行环境 | 🌐 浏览器 + Node.js | 🖥️ 仅 Node.js | 🖥️ 仅 Node.js | 🖥️ 仅 Node.js |
| API 风格 | ⚡ Promise 异步 | 🛑 同步阻塞 | 🌊 流式管道 | 🕰️ 旧式回调 |
| 大文件支持 | ⚠️ 内存受限 | ⚠️ 内存受限 | ✅ 流式低内存 | ⚠️ 未知风险 |
| 维护状态 | ✅ 活跃 | ✅ 稳定 | ✅ 活跃 | ❌ 已弃用 |
| 典型场景 | 前端上传下载 | 后端脚本工具 | 服务端大文件归档 | 无 (请避免) |
jszip 是通用性最好的选择 🌟。如果你的项目涉及前端交互,或者希望代码能在全栈运行,它是首选。它的 Promise API 让代码更清晰,社区支持也最强大。
adm-zip 适合简单的后端脚本 🛠️。如果你只是在 Node.js 里写个工具压缩几个配置文件,它的同步 API 写起来最快,不需要处理异步流程。
zip-stream 是处理大文件的专家 🐘。当你要压缩日志文件或用户上传的大包时,用它可以避免服务器内存爆满。配合 archiver 使用效果更佳。
node-zip 请直接忽略 🚫。它已经完成了历史使命,现在使用它只会带来维护负担和安全风险。
总结:现代开发中,优先选 jszip 保证兼容性;服务端大文件选 zip-stream 保证性能;简单脚本选 adm-zip 保证效率;永远避开 node-zip。
选择 adm-zip 如果你在 Node.js 环境中编写命令行工具或脚本,需要同步读写本地文件,且处理的文件体积较小。它的 API 简单直接,不需要处理异步回调,但不适合浏览器或大文件场景。
选择 jszip 如果你需要在浏览器中直接处理压缩文件,或者希望有一套统一的异步 API 同时运行在 Node.js 和前端。它基于 Promise,易于与现代 async/await 代码集成,生态最活跃。
不要选择 node-zip。这个项目已经多年未更新,官方已不再维护,存在潜在的安全风险和兼容性问题。在新项目中请直接使用 jszip 或 adm-zip 代替。
选择 zip-stream 如果你在 Node.js 服务端处理超大文件或需要流式传输(例如直接管道到 HTTP 响应)。它允许逐文件添加而不必将所有内容加载到内存,但 API 相对底层,配置较复杂。
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 });
.
.
.
Please report security vulnerabilities privately. See SECURITY.md.