function Extract(opts) { var self = this; if (!(this instanceof Extract)) { return new Extract(opts); } Writable.apply(this); this._opts = opts || { verbose: false }; this._parser = Parse(this._opts); this._parser.on('error', function(err) { self.emit('error', err); }); this.on('finish', function() { self._parser.end(); }); var writer = Writer({ type: 'Directory', path: opts.path }); writer.on('error', function(err) { self.emit('error', err); }); writer.on('close', function() { self.emit('close') }); this.on('pipe', function(source) { if (opts.verbose && source.path) { console.log('Archive: ', source.path); } }); this._parser.pipe(writer); }
...
$ npm install unzip2
```
## Quick Examples
### Extract to a directory
```javascript
fs.createReadStream('path/to/archive.zip').pipe(unzip.Extract({ path: '
;output/path' }));
```
Extract emits the 'close' event once the zip's contents have been fully extracted to disk.
### Parse zip file contents
Process each zip file entry or pipe entries to another stream.
...
function Parse(opts) { var self = this; if (!(this instanceof Parse)) { return new Parse(opts); } Transform.call(this, { lowWaterMark: 0 }); this._opts = opts || { verbose: false }; this._hasEntryListener = false; this._pullStream = new PullStream(); this._pullStream.on("error", function (e) { self.emit('error', e); }); this._pullStream.once("end", function () { self._streamEnd = true; }); this._pullStream.once("finish", function () { self._streamFinish = true; }); this._readRecord(); }
...
Process each zip file entry or pipe entries to another stream.
__Important__: If you do not intend to consume an entry stream's raw data, call autodrain() to dispose of the entry's
contents. Otherwise you risk running out of memory.
```javascript
fs.createReadStream('path/to/archive.zip')
.pipe(unzip.Parse())
.on('entry', function (entry) {
var fileName = entry.path;
var type = entry.type; // 'Directory' or 'File'
var size = entry.size;
if (fileName === "this IS the file I'm looking for") {
entry.pipe(fs.createWriteStream('output/path'));
} else {
...
function Entry() { PassThrough.call(this); this.props = {}; }
n/a
function Extract(opts) { var self = this; if (!(this instanceof Extract)) { return new Extract(opts); } Writable.apply(this); this._opts = opts || { verbose: false }; this._parser = Parse(this._opts); this._parser.on('error', function(err) { self.emit('error', err); }); this.on('finish', function() { self._parser.end(); }); var writer = Writer({ type: 'Directory', path: opts.path }); writer.on('error', function(err) { self.emit('error', err); }); writer.on('close', function() { self.emit('close') }); this.on('pipe', function(source) { if (opts.verbose && source.path) { console.log('Archive: ', source.path); } }); this._parser.pipe(writer); }
...
$ npm install unzip2
```
## Quick Examples
### Extract to a directory
```javascript
fs.createReadStream('path/to/archive.zip').pipe(unzip.Extract({ path: '
;output/path' }));
```
Extract emits the 'close' event once the zip's contents have been fully extracted to disk.
### Parse zip file contents
Process each zip file entry or pipe entries to another stream.
...
function Writable(options) { // Writable ctor is applied to Duplexes, too. // `realHasInstance` is necessary because using plain `instanceof` // would return false, as no `_writableState` property is attached. // Trying to use the custom `instanceof` for Writable here will also break the // Node.js LazyTransform implementation, which has a non-trivial getter for // `_writableState` that would lead to infinite recursion. if (!(realHasInstance.call(Writable, this)) && !(this instanceof Stream.Duplex)) { return new Writable(options); } this._writableState = new WritableState(options, this); // legacy. this.writable = true; if (options) { if (typeof options.write === 'function') this._write = options.write; if (typeof options.writev === 'function') this._writev = options.writev; } Stream.call(this); }
n/a
_write = function (chunk, encoding, callback) { if (this._parser.write(chunk)) { return callback(); } return this._parser.once('drain', callback); }
n/a
function Parse(opts) { var self = this; if (!(this instanceof Parse)) { return new Parse(opts); } Transform.call(this, { lowWaterMark: 0 }); this._opts = opts || { verbose: false }; this._hasEntryListener = false; this._pullStream = new PullStream(); this._pullStream.on("error", function (e) { self.emit('error', e); }); this._pullStream.once("end", function () { self._streamEnd = true; }); this._pullStream.once("finish", function () { self._streamFinish = true; }); this._readRecord(); }
...
Process each zip file entry or pipe entries to another stream.
__Important__: If you do not intend to consume an entry stream's raw data, call autodrain() to dispose of the entry's
contents. Otherwise you risk running out of memory.
```javascript
fs.createReadStream('path/to/archive.zip')
.pipe(unzip.Parse())
.on('entry', function (entry) {
var fileName = entry.path;
var type = entry.type; // 'Directory' or 'File'
var size = entry.size;
if (fileName === "this IS the file I'm looking for") {
entry.pipe(fs.createWriteStream('output/path'));
} else {
...
function Parse(opts) { var self = this; if (!(this instanceof Parse)) { return new Parse(opts); } Transform.call(this, { lowWaterMark: 0 }); this._opts = opts || { verbose: false }; this._hasEntryListener = false; this._pullStream = new PullStream(); this._pullStream.on("error", function (e) { self.emit('error', e); }); this._pullStream.once("end", function () { self._streamEnd = true; }); this._pullStream.once("finish", function () { self._streamFinish = true; }); this._readRecord(); }
n/a
function Transform(options) { if (!(this instanceof Transform)) return new Transform(options); Duplex.call(this, options); this._transformState = new TransformState(this); var stream = this; // start out asking for a readable event once data is transformed. this._readableState.needReadable = true; // we have implemented the _read method, and done the other things // that Readable wants before the first _read call, so unset the // sync guard flag. this._readableState.sync = false; if (options) { if (typeof options.transform === 'function') this._transform = options.transform; if (typeof options.flush === 'function') this._flush = options.flush; } // When the writable side finishes, then flush out anything remaining. this.once('prefinish', function() { if (typeof this._flush === 'function') this._flush(function(er) { done(stream, er); }); else done(stream); }); }
n/a
_flush = function (callback) { if (!this._streamEnd || !this._streamFinish) { return setImmediate(this._flush.bind(this, callback)); } this.emit('close'); return callback(); }
n/a
_processDataDescriptor = function (entry) { var self = this; this._pullStream.pull(16, function (err, data) { if (err) { return self.emit('error', err); } var vars = binary.parse(data) .word32lu('dataDescriptorSignature') .word32lu('crc32') .word32lu('compressedSize') .word32lu('uncompressedSize') .vars; entry.size = vars.uncompressedSize; self._readRecord(); }); }
n/a
_readCentralDirectoryFileHeader = function () { var self = this; this._pullStream.pull(42, function (err, data) { if (err) { return self.emit('error', err); } var vars = binary.parse(data) .word16lu('versionMadeBy') .word16lu('versionsNeededToExtract') .word16lu('flags') .word16lu('compressionMethod') .word16lu('lastModifiedTime') .word16lu('lastModifiedDate') .word32lu('crc32') .word32lu('compressedSize') .word32lu('uncompressedSize') .word16lu('fileNameLength') .word16lu('extraFieldLength') .word16lu('fileCommentLength') .word16lu('diskNumber') .word16lu('internalFileAttributes') .word32lu('externalFileAttributes') .word32lu('offsetToLocalFileHeader') .vars; return self._pullStream.pull(vars.fileNameLength, function (err, fileName) { if (err) { return self.emit('error', err); } fileName = fileName.toString('utf8'); self._pullStream.pull(vars.extraFieldLength, function (err, extraField) { if (err) { return self.emit('error', err); } self._pullStream.pull(vars.fileCommentLength, function (err, fileComment) { if (err) { return self.emit('error', err); } return self._readRecord(); }); }); }); }); }
n/a
_readEndOfCentralDirectoryRecord = function () { var self = this; this._pullStream.pull(18, function (err, data) { if (err) { return self.emit('error', err); } var vars = binary.parse(data) .word16lu('diskNumber') .word16lu('diskStart') .word16lu('numberOfRecordsOnDisk') .word16lu('numberOfRecords') .word32lu('sizeOfCentralDirectory') .word32lu('offsetToStartOfCentralDirectory') .word16lu('commentLength') .vars; if (vars.commentLength) { setImmediate(function() { self._pullStream.pull(vars.commentLength, function (err, comment) { if (err) { return self.emit('error', err); } comment = comment.toString('utf8'); return self._pullStream.end(); }); }); } else { self._pullStream.end(); } }); }
n/a
_readFile = function () { var self = this; this._pullStream.pull(26, function (err, data) { if (err) { return self.emit('error', err); } var vars = binary.parse(data) .word16lu('versionsNeededToExtract') .word16lu('flags') .word16lu('compressionMethod') .word16lu('lastModifiedTime') .word16lu('lastModifiedDate') .word32lu('crc32') .word32lu('compressedSize') .word32lu('uncompressedSize') .word16lu('fileNameLength') .word16lu('extraFieldLength') .vars; return self._pullStream.pull(vars.fileNameLength, function (err, fileName) { if (err) { return self.emit('error', err); } fileName = fileName.toString('utf8'); var entry = new Entry(); entry.path = fileName; entry.props.path = fileName; entry.type = (vars.compressedSize === 0 && /[\/\\]$/.test(fileName)) ? 'Directory' : 'File'; if (self._opts.verbose) { if (entry.type === 'Directory') { console.log(' creating:', fileName); } else if (entry.type === 'File') { if (vars.compressionMethod === 0) { console.log(' extracting:', fileName); } else { console.log(' inflating:', fileName); } } } var hasEntryListener = self._hasEntryListener; if (hasEntryListener) { self.emit('entry', entry); } self._pullStream.pull(vars.extraFieldLength, function (err, extraField) { if (err) { return self.emit('error', err); } if (entry.type === 'Directory') { self._pullStream.pull(vars.compressedSize, function (err, compressedData) { if (err) { return self.emit('error', err); } if (hasEntryListener) { entry.write(compressedData); entry.end(); } return self._readRecord(); }); } else { var fileSizeKnown = !(vars.flags & 0x08); var has_compression = !(vars.compressionMethod === 0); var inflater; if(has_compression) { inflater = zlib.createInflateRaw(); inflater.on('error', function (err) { self.emit('error', err); }); } if (fileSizeKnown) { entry.size = vars.uncompressedSize; if (hasEntryListener) { entry.on('finish', self._readRecord.bind(self)); if(has_compression) { self._pullStream.pipe(vars.compressedSize, inflater).pipe(entry); } else { self._pullStream.pipe(vars.compressedSize, entry); } } else { self._pullStream.drain(vars.compressedSize, function (err) { if (err) { return self.emit('error', err); } self._readRecord(); }); } } else { var descriptorSig = new Buffer(4); descriptorSig.writeUInt32LE(0x08074b50, 0); var matchStream = new MatchStream({ pattern: descriptorSig }, function (buf, matched, extra) { if (hasEntryListener) { if (!matched) { return this.push(buf); } this.push(buf); } self._pullStream.unpipe(); self._pullStream.prepend(extra); setImmediate(function() { self._processDataDescriptor(entry); }); return this.push(null); }); self._pullStream.pipe(matchStream); if (hasEntryListener) { if(has_compression) { matchStream.pipe(inflater).pipe(entry); } else { matchStream.pipe(entry); } } } } }); }); }); }
n/a
_readRecord = function () { var self = this; this._pullStream.pull(4, function (err, data) { if (err) { return self.emit('error', err); } if (data.length === 0) { return; } var signature = data.readUInt32LE(0); if (signature === 0x04034b50) { self._readFile(); } else if (signature === 0x02014b50) { self._readCentralDirectoryFileHeader(); } else if (signature === 0x06054b50) { self._readEndOfCentralDirectoryRecord(); } else { err = new Error('invalid signature: 0x' + signature.toString(16)); self.emit('error', err); } }); }
n/a
_transform = function (chunk, encoding, callback) { if (this._pullStream.write(chunk)) { return callback(); } this._pullStream.once('drain', callback); }
n/a
addListener = function (type, listener) { if ('entry' === type) { this._hasEntryListener = true; } return Transform.prototype.addListener.call(this, type, listener); }
n/a
on = function (type, listener) { if ('entry' === type) { this._hasEntryListener = true; } return Transform.prototype.addListener.call(this, type, listener); }
...
__Important__: If you do not intend to consume an entry stream's raw data, call autodrain() to dispose of the entry's
contents. Otherwise you risk running out of memory.
```javascript
fs.createReadStream('path/to/archive.zip')
.pipe(unzip.Parse())
.on('entry', function (entry) {
var fileName = entry.path;
var type = entry.type; // 'Directory' or 'File'
var size = entry.size;
if (fileName === "this IS the file I'm looking for") {
entry.pipe(fs.createWriteStream('output/path'));
} else {
entry.autodrain();
...
pipe = function (dest, opts) { var self = this; if (typeof dest.add === "function") { self.on("entry", function (entry) { dest.add(entry); }) } return Transform.prototype.pipe.apply(this, arguments); }
...
$ npm install unzip2
```
## Quick Examples
### Extract to a directory
```javascript
fs.createReadStream('path/to/archive.zip').pipe(unzip.Extract({ path: '
;output/path' }));
```
Extract emits the 'close' event once the zip's contents have been fully extracted to disk.
### Parse zip file contents
Process each zip file entry or pipe entries to another stream.
...
function Entry() { PassThrough.call(this); this.props = {}; }
n/a
function PassThrough(options) { if (!(this instanceof PassThrough)) return new PassThrough(options); Transform.call(this, options); }
n/a
autodrain = function () { this.on('readable', this.read.bind(this)); }
...
.on('entry', function (entry) {
var fileName = entry.path;
var type = entry.type; // 'Directory' or 'File'
var size = entry.size;
if (fileName === "this IS the file I'm looking for") {
entry.pipe(fs.createWriteStream('output/path'));
} else {
entry.autodrain();
}
});
```
Or pipe the output of unzip.Parse() to fstream
```javascript
...