0
# Unzip
1
2
Unzip is a streaming cross-platform unzip library for Node.js that provides simple APIs for parsing and extracting zip files. It offers compatibility with fstream and fs.ReadStream interfaces without compiled dependencies, using Node.js's built-in zlib support for inflation.
3
4
## Package Information
5
6
- **Package Name**: unzip
7
- **Package Type**: npm
8
- **Language**: JavaScript (Node.js)
9
- **Installation**: `npm install unzip`
10
11
## Core Imports
12
13
```javascript
14
const unzip = require('unzip');
15
// Or destructured
16
const { Parse, Extract } = require('unzip');
17
```
18
19
ES6 modules (if supported by your Node.js version):
20
21
```javascript
22
import unzip from 'unzip';
23
import { Parse, Extract } from 'unzip';
24
```
25
26
## Basic Usage
27
28
### Extract to Directory
29
30
```javascript
31
const fs = require('fs');
32
const unzip = require('unzip');
33
34
// Extract entire zip archive to a directory
35
fs.createReadStream('path/to/archive.zip')
36
.pipe(unzip.Extract({ path: 'output/path' }));
37
```
38
39
### Parse and Process Entries
40
41
```javascript
42
const fs = require('fs');
43
const unzip = require('unzip');
44
45
// Parse zip file and process individual entries
46
fs.createReadStream('path/to/archive.zip')
47
.pipe(unzip.Parse())
48
.on('entry', function (entry) {
49
const fileName = entry.path;
50
const type = entry.type; // 'Directory' or 'File'
51
const size = entry.size;
52
53
if (fileName === "target-file.txt") {
54
entry.pipe(fs.createWriteStream('output.txt'));
55
} else {
56
entry.autodrain(); // Important: drain unused entries
57
}
58
});
59
```
60
61
## Architecture
62
63
Unzip is built around three core components:
64
65
- **Parse**: Transform stream that parses zip archive structure and emits entry events
66
- **Extract**: Writable stream that extracts entire archives to directories using fstream
67
- **Entry**: PassThrough stream representing individual zip entries (files/directories)
68
69
The library uses a streaming approach for memory efficiency, processing zip files without loading entire contents into memory.
70
71
## Capabilities
72
73
### Zip Archive Parsing
74
75
Parse zip files and access individual entries with streaming support.
76
77
```javascript { .api }
78
/**
79
* Creates a streaming zip parser (can be called with or without 'new')
80
* @param {Object} opts - Configuration options
81
* @param {boolean} opts.verbose - Enable verbose logging (default: false)
82
* @returns {Parse} Transform stream for parsing zip archives
83
*/
84
function Parse(opts);
85
86
/**
87
* Factory method equivalent to new Parse(opts) - preferred way to create instances
88
* @param {Object} opts - Configuration options
89
* @returns {Parse} Transform stream instance
90
*/
91
Parse.create = function(opts);
92
93
/**
94
* Enhanced pipe method with fstream compatibility
95
* Automatically calls dest.add(entry) for each entry if destination has an add method
96
* @param {Object} dest - Destination stream or fstream Writer
97
* @param {Object} opts - Standard pipe options
98
* @returns {Object} The destination stream
99
*/
100
Parse.prototype.pipe = function(dest, opts);
101
102
/**
103
* Enhanced event listener registration that tracks 'entry' listeners
104
* When entry listeners are added, the parser will emit entry events and provide entry streams
105
* @param {string} type - Event type ('entry', 'error', 'close', etc.)
106
* @param {Function} listener - Event handler function
107
* @returns {Parse} This Parse instance for chaining
108
*/
109
Parse.prototype.addListener = function(type, listener);
110
Parse.prototype.on = function(type, listener); // Alias for addListener
111
```
112
113
The Parse stream emits the following events:
114
115
- **'entry'** - Emitted for each zip entry (file/directory)
116
- **'error'** - Emitted on parsing errors
117
- **'close'** - Emitted when parsing completes
118
- **'end'** - Emitted when stream ends
119
- **'finish'** - Emitted when stream finishes
120
121
### Directory Extraction
122
123
Extract entire zip archives to filesystem directories.
124
125
```javascript { .api }
126
/**
127
* Creates a writable stream for extracting zip archives to directories (can be called with or without 'new')
128
* @param {Object} opts - Configuration options
129
* @param {string} opts.path - Target extraction directory (required)
130
* @param {boolean} opts.verbose - Enable verbose logging (default: false)
131
* @returns {Extract} Writable stream for zip extraction
132
*/
133
function Extract(opts);
134
```
135
136
The Extract stream emits the following events:
137
138
- **'error'** - Emitted on extraction errors
139
- **'close'** - Emitted when extraction completes
140
- **'pipe'** - Emitted when piped to
141
- **'finish'** - Emitted when stream finishes
142
143
### Zip Entry Processing
144
145
Individual zip entries are represented as Entry streams.
146
147
```javascript { .api }
148
/**
149
* PassThrough stream representing a zip entry
150
* Note: Entry instances are created internally by Parse, not directly by users
151
* @constructor
152
*/
153
function Entry();
154
155
/**
156
* Automatically drain entry content to prevent memory issues
157
* Call this for entries you don't intend to process
158
*/
159
Entry.prototype.autodrain = function();
160
```
161
162
Entry objects have the following properties (set by Parse during processing):
163
164
- **path** (string) - Entry file path within the zip archive
165
- **type** (string) - Entry type: 'File' or 'Directory' (determined by compressed size and path ending)
166
- **size** (number) - Entry uncompressed size (available after processing, may be undefined during parsing)
167
- **props** (object) - Additional entry properties including a copy of the path
168
169
## Types
170
171
```javascript { .api }
172
/**
173
* Parse stream class (extends Node.js Transform stream)
174
*/
175
class Parse {
176
constructor(opts);
177
178
// Enhanced pipe method with automatic fstream compatibility
179
// Calls dest.add(entry) for each entry if destination has add method
180
pipe(dest, opts);
181
182
// Enhanced event listener methods that track 'entry' listeners
183
// When entry listeners are registered, parser provides entry streams
184
addListener(type, listener);
185
on(type, listener); // Alias for addListener
186
187
// Standard Transform stream methods available
188
write(chunk, encoding, callback);
189
end();
190
// ... other Transform stream methods
191
}
192
193
/**
194
* Extract stream class (extends Node.js Writable stream)
195
*/
196
class Extract {
197
constructor(opts);
198
199
// Standard Writable stream methods available
200
write(chunk, encoding, callback);
201
end();
202
// ... other Writable stream methods
203
}
204
205
/**
206
* Entry stream class (extends Node.js PassThrough stream)
207
*/
208
class Entry {
209
constructor();
210
autodrain();
211
212
// Properties set by Parse during zip processing
213
path: string;
214
type: 'File' | 'Directory';
215
size: number;
216
props: object;
217
218
// Standard PassThrough stream methods available
219
pipe(destination, options);
220
read(size);
221
write(chunk, encoding, callback);
222
// ... other stream methods
223
}
224
225
/**
226
* Configuration options for Parse
227
*/
228
interface ParseOptions {
229
verbose?: boolean;
230
}
231
232
/**
233
* Configuration options for Extract
234
*/
235
interface ExtractOptions {
236
path: string;
237
verbose?: boolean;
238
}
239
```
240
241
## Error Handling
242
243
The library emits errors for various conditions:
244
245
- **Invalid zip signatures**: Throws errors with signature details (e.g., "invalid signature: 0x12345678")
246
- **Stream errors**: Propagated through 'error' events on Parse and Extract streams
247
- **Compression errors**: zlib inflation errors are propagated through the error event chain
248
249
```javascript
250
const parser = unzip.Parse();
251
parser.on('error', function(err) {
252
console.error('Parse error:', err.message);
253
});
254
255
const extractor = unzip.Extract({ path: './output' });
256
extractor.on('error', function(err) {
257
console.error('Extract error:', err.message);
258
});
259
```
260
261
## Advanced Usage
262
263
### Pipe to fstream Writer
264
265
```javascript
266
const fs = require('fs');
267
const fstream = require('fstream');
268
const unzip = require('unzip');
269
270
const readStream = fs.createReadStream('archive.zip');
271
const writeStream = fstream.Writer('output/path');
272
273
readStream
274
.pipe(unzip.Parse())
275
.pipe(writeStream);
276
```
277
278
### Selective File Extraction
279
280
```javascript
281
fs.createReadStream('archive.zip')
282
.pipe(unzip.Parse())
283
.on('entry', function (entry) {
284
if (entry.path.endsWith('.txt')) {
285
// Extract only text files
286
entry.pipe(fs.createWriteStream(`output/${entry.path}`));
287
} else {
288
// Skip other files
289
entry.autodrain();
290
}
291
});
292
```
293
294
### Memory Management
295
296
**Important**: Always call `entry.autodrain()` for entries you don't process to prevent memory leaks:
297
298
```javascript
299
fs.createReadStream('large-archive.zip')
300
.pipe(unzip.Parse())
301
.on('entry', function (entry) {
302
if (entry.type === 'Directory') {
303
// Skip directories
304
entry.autodrain();
305
} else if (entry.size > 1000000) {
306
// Skip large files
307
entry.autodrain();
308
} else {
309
// Process small files
310
entry.pipe(fs.createWriteStream(entry.path));
311
}
312
});
313
```
314
315
### Enhanced Parse Class Features
316
317
#### Automatic fstream Compatibility
318
319
The Parse class automatically detects when piped to fstream destinations and calls `dest.add(entry)` for each zip entry:
320
321
```javascript
322
// Enhanced pipe method detects fstream Writers and calls add() automatically
323
fs.createReadStream("archive.zip")
324
.pipe(unzip.Parse())
325
.pipe(fstream.Writer("output/path")); // Automatically calls writeStream.add(entry)
326
```
327
328
#### Entry Listener Optimization
329
330
The Parse class optimizes behavior based on whether entry listeners are registered:
331
332
```javascript
333
// Without entry listeners - entries are not processed into streams (memory efficient)
334
fs.createReadStream("archive.zip")
335
.pipe(unzip.Parse())
336
.pipe(fstream.Writer("output"));
337
338
// With entry listeners - entries become readable streams
339
fs.createReadStream("archive.zip")
340
.pipe(unzip.Parse())
341
.on("entry", function(entry) {
342
// Entry is now a readable stream with available properties
343
console.log("Processing:", entry.path, "Type:", entry.type);
344
if (entry.size) console.log("Size:", entry.size);
345
entry.autodrain(); // Important: drain if not processing
346
});
347
```
348