adm-zip、jszip、node-zip、zip-stream は、JavaScript 環境で ZIP ファイルの作成や展開を行うためのライブラリです。それぞれが異なる実行モデル(同期・非同期・ストリーミング)と対応環境(Node.js・ブラウザ)を持っており、プロジェクトの要件に応じて適切なものを選ぶ必要があります。jszip はブラウザと Node.js の両方で動作する汎用性の高いライブラリであり、adm-zip は Node.js 向けの同期処理に最適化されています。zip-stream は大容量ファイルを扱う際のストリーミング処理に特化しており、node-zip は長期間メンテナンスされていないため新規プロジェクトでの使用は推奨されません。
JavaScript で ZIP ファイルを扱う場合、どのライブラリを選ぶべきかはプロジェクトの環境(Node.js かブラウザか)と、処理方式(同期か非同期か)によって大きく変わります。adm-zip、jszip、node-zip、zip-stream はそれぞれ異なるアプローチを取っており、誤った選択をするとパフォーマンス問題や保守性の低下を招きます。ここでは、実務的な観点からこれらを比較します。
ライブラリごとの最大の違いは、処理がどのように行われるかです。
adm-zip は同期処理を基本としています。
fs)を直接操作します。// adm-zip: 同期処理の例
const AdmZip = require('adm-zip');
const zip = new AdmZip();
zip.addLocalFile('./path/to/file.txt');
zip.writeZip('./output.zip'); // 完了するまで処理が止まる
jszip は非同期処理(Promise)を基本としています。
await による制御が必要です。// jszip: 非同期処理の例
const JSZip = require('jszip');
const zip = new JSZip();
zip.file('file.txt', 'content');
// generateAsync で完了を待つ
const content = await zip.generateAsync({ type: 'nodebuffer' });
zip-stream はストリーミング処理に特化しています。
stream モジュールと相性が良いです。// zip-stream: ストリーミング処理の例
const ZipStream = require('zip-stream');
const fs = require('fs');
const archive = new ZipStream();
const output = fs.createWriteStream('./output.zip');
archive.pipe(output);
archive.file('./large-file.txt', { name: 'large-file.txt' });
archive.finalize(); // ストリームを終了
node-zip は古い同期/コールバックスタイルです。
// node-zip: 古いスタイルの例(非推奨)
const zip = require('node-zip')();
zip.file('file.txt', 'content');
const data = zip.generate({ type: 'nodebuffer' });
// 現代の Promise ベースの扱いが難しい
どこで動かすかも重要な選定基準です。
adm-zip は Node.js 専用です。
fs モジュールに依存しているため、ブラウザでは動作しません。// adm-zip: Node.js 専用
// ブラウザで使うと 'fs' モジュールが見つからないエラーが出る
const AdmZip = require('adm-zip');
jszip はユニバーサル(ブラウザ + Node.js)です。
// jszip: 環境を選ばない
// ブラウザでも Node.js でも同じ API で動作する
const JSZip = require('jszip');
zip-stream は Node.js 専用です。
// zip-stream: Node.js ストリーム依存
const { Writable } = require('stream'); // Node.js 固有
node-zip は本来 Node.js 向けですが、古すぎます。
// node-zip: 環境依存性が古く、現代のバンドラと相性が悪い
ライブラリのメンテナンス状況は、セキュリティと長期運用に直結します。
adm-zip は活発にメンテナンスされています。
jszip も非常に安定しています。
zip-stream は archiver エコシステムの一部です。
node-zip は保守が終了しています。
実際のコードでどのように違うか見てみましょう。
// adm-zip
zip.addFile('text.txt', Buffer.from('content'));
// jszip
zip.file('text.txt', 'content');
// node-zip
zip.file('text.txt', 'content');
// zip-stream
archive.entry({ name: 'text.txt' }, (err, entry) => {
entry.end('content');
});
// adm-zip
zip.writeZip('./output.zip');
// jszip
const buffer = await zip.generateAsync({ type: 'nodebuffer' });
fs.writeFileSync('./output.zip', buffer);
// node-zip
const data = zip.generate({ type: 'nodebuffer' });
fs.writeFileSync('./output.zip', data);
// zip-stream
archive.finalize(); // ストリーム経由で出力先に書き込まれる
| 特徴 | adm-zip | jszip | node-zip | zip-stream |
|---|---|---|---|---|
| 実行モデル | 同期 | 非同期 (Promise) | 同期/コールバック | ストリーミング |
| 対応環境 | Node.js | Node.js + ブラウザ | Node.js (旧) | Node.js |
| 保守状況 | 活発 | 活発 | 終了 (非推奨) | 活発 |
| メモリ効率 | 低 (全量ロード) | 中 | 低 | 高 (ストリーム) |
| 推奨度 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ❌ | ⭐⭐⭐⭐ |
jszip が最もバランスの取れた選択肢です。
adm-zip は Node.js 専用ツールに限定して使います。
zip-stream は特殊なケースで使います。
archiver などのラッパーライブラリ経由で使用します。node-zip は使用しないでください。
最終的には、「ブラウザで動く必要があるか」 と 「ファイルサイズは大きいか」 の 2 点で決定すると良いでしょう。ほとんどの Web アプリケーションでは jszip が正解になります。
Node.js 環境で動作するツールや CLI アプリケーションを開発しており、同期処理で簡潔にコードを書きたい場合に選択します。ファイルシステムへの直接アクセスが必要で、ブラウザ対応が不要なプロジェクトに適しています。
ブラウザ上で ZIP ファイルを処理する必要がある場合、または Node.js でも非同期(Promise)ベースの処理を好む場合に選択します。汎用性が高く、コミュニティも活発なため、多くの Web アプリケーションで標準的な選択肢となります。
このパッケージは長期間更新されておらず、保守が終了しているため、新規プロジェクトでは使用しないでください。代わりに adm-zip や jszip への移行を検討すべきです。
Node.js 環境で非常に大きなファイルを処理する場合や、メモリ使用量を抑えるためにストリーミング処理が必要な場合に選択します。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 });
.
.
.