Zlib
- Zlib
- Threadpool usage and performance considerations
- Compressing HTTP requests and responses
- Memory usage tuning
- Flushing
- Constants
- Class: Options
- Class: BrotliOptions
- Class: zlib.BrotliCompress
- Class: zlib.BrotliDecompress
- Class: zlib.Deflate
- Class: zlib.DeflateRaw
- Class: zlib.Gunzip
- Class: zlib.Gzip
- Class: zlib.Inflate
- Class: zlib.InflateRaw
- Class: zlib.Unzip
- Class: zlib.ZipBuffer
- new zlib.ZipBuffer(buffer)
- zipBuffer.add(filename, data[, options])
- zipBuffer.addSync(filename, data[, options])
- zipBuffer.addEntry(entry)
- zipBuffer.clear()
- zipBuffer.comment
- zipBuffer.delete(name)
- zipBuffer.entries()
- zipBuffer.forEach(callback[, thisArg])
- zipBuffer.get(name)
- zipBuffer.has(name)
- zipBuffer.keys()
- zipBuffer.size
- zipBuffer.toBuffer([options])
- zipBuffer.toBufferSync([options])
- zipBuffer.values()
- zipBuffer.writable
- Class: zlib.ZipEntry
- Static method: zlib.ZipEntry.create(filename, data[, options])
- Static method: zlib.ZipEntry.createStream(filename, source[, options])
- Static method: zlib.ZipEntry.createSymlink(filename, target[, options])
- Static method: zlib.ZipEntry.createSync(filename, data[, options])
- Static method: zlib.ZipEntry.read(buffer)
- zipEntry.comment
- zipEntry.compressed
- zipEntry.compressedSize
- zipEntry.content([options])
<!--introduced_in=v0.10.0-->
Stability: 2 - Stable
<!-- source_link=lib/zlib.js -->
The node:zlib module provides compression functionality implemented using
Gzip, Deflate/Inflate, Brotli, and Zstd.
To access it:
import zlib from 'node:zlib';
const zlib = require('node:zlib');
Compression and decompression are built around the Node.js [Streams API][].
Compressing or decompressing a stream (such as a file) can be accomplished by
piping the source stream through a zlib Transform stream into a destination
stream:
import {
createReadStream,
createWriteStream,
} from 'node:fs';
import process from 'node:process';
import { createGzip } from 'node:zlib';
import { pipeline } from 'node:stream';
const gzip = createGzip();
const source = createReadStream('input.txt');
const destination = createWriteStream('input.txt.gz');
pipeline(source, gzip, destination, (err) => {
if (err) {
console.error('An error occurred:', err);
process.exitCode = 1;
}
});
const {
createReadStream,
createWriteStream,
} = require('node:fs');
const { createGzip } = require('node:zlib');
const { pipeline } = require('node:stream');
const gzip = createGzip();
const source = createReadStream('input.txt');
const destination = createWriteStream('input.txt.gz');
pipeline(source, gzip, destination, (err) => {
if (err) {
console.error('An error occurred:', err);
process.exitCode = 1;
}
});
Or, using the promise pipeline API:
import {
createReadStream,
createWriteStream,
} from 'node:fs';
import { createGzip } from 'node:zlib';
import { pipeline } from 'node:stream/promises';
async function do_gzip(input, output) {
const gzip = createGzip();
const source = createReadStream(input);
const destination = createWriteStream(output);
await pipeline(source, gzip, destination);
}
await do_gzip('input.txt', 'input.txt.gz');
const {
createReadStream,
createWriteStream,
} = require('node:fs');
const { createGzip } = require('node:zlib');
const { pipeline } = require('node:stream/promises');
async function do_gzip(input, output) {
const gzip = createGzip();
const source = createReadStream(input);
const destination = createWriteStream(output);
await pipeline(source, gzip, destination);
}
do_gzip('input.txt', 'input.txt.gz')
.catch((err) => {
console.error('An error occurred:', err);
process.exitCode = 1;
});
It is also possible to compress or decompress data in a single step:
import process from 'node:process';
import { Buffer } from 'node:buffer';
import { deflate, unzip } from 'node:zlib';
const input = '.................................';
deflate(input, (err, buffer) => {
if (err) {
console.error('An error occurred:', err);
process.exitCode = 1;
}
console.log(buffer.toString('base64'));
});
const buffer = Buffer.from('eJzT0yMAAGTvBe8=', 'base64');
unzip(buffer, (err, buffer) => {
if (err) {
console.error('An error occurred:', err);
process.exitCode = 1;
}
console.log(buffer.toString());
});
// Or, Promisified
import { promisify } from 'node:util';
const do_unzip = promisify(unzip);
const unzippedBuffer = await do_unzip(buffer);
console.log(unzippedBuffer.toString());
const { deflate, unzip } = require('node:zlib');
const input = '.................................';
deflate(input, (err, buffer) => {
if (err) {
console.error('An error occurred:', err);
process.exitCode = 1;
}
console.log(buffer.toString('base64'));
});
const buffer = Buffer.from('eJzT0yMAAGTvBe8=', 'base64');
unzip(buffer, (err, buffer) => {
if (err) {
console.error('An error occurred:', err);
process.exitCode = 1;
}
console.log(buffer.toString());
});
// Or, Promisified
const { promisify } = require('node:util');
const do_unzip = promisify(unzip);
do_unzip(buffer)
.then((buf) => console.log(buf.toString()))
.catch((err) => {
console.error('An error occurred:', err);
process.exitCode = 1;
});
Threadpool usage and performance considerations
All zlib APIs, except those that are explicitly synchronous, use the Node.js
internal threadpool. This can lead to surprising effects and performance
limitations in some applications.
Creating and using a large number of zlib objects simultaneously can cause significant memory fragmentation.
import zlib from 'node:zlib';
import { Buffer } from 'node:buffer';
const payload = Buffer.from('This is some data');
// WARNING: DO NOT DO THIS!
for (let i = 0; i < 30000; ++i) {
zlib.deflate(payload, (err, buffer) => {});
}
const zlib = require('node:zlib');
const payload = Buffer.from('This is some data');
// WARNING: DO NOT DO THIS!
for (let i = 0; i < 30000; ++i) {
zlib.deflate(payload, (err, buffer) => {});
}
In the preceding example, 30,000 deflate instances are created concurrently. Because of how some operating systems handle memory allocation and deallocation, this may lead to significant memory fragmentation.
It is strongly recommended that the results of compression operations be cached to avoid duplication of effort.
Compressing HTTP requests and responses
The node:zlib module can be used to implement support for the gzip, deflate,
br, and zstd content-encoding mechanisms defined by
[HTTP](https://tools.ietf.org/html/rfc7230#section-4.2.
The HTTP [Accept-Encoding][] header is used within an HTTP request to identify
the compression encodings accepted by the client. The [Content-Encoding][]
header is used to identify the compression encodings actually applied to a
message.
The examples given below are drastically simplified to show the basic concept.
Using zlib encoding can be expensive, and the results ought to be cached.
See [Memory usage tuning][] for more information on the speed/memory/compression
tradeoffs involved in zlib usage.
// Client request example
import fs from 'node:fs';
import zlib from 'node:zlib';
import http from 'node:http';
import process from 'node:process';
import { pipeline } from 'node:stream';
const request = http.get({ host: 'example.com',
path: '/',
port: 80,
headers: { 'Accept-Encoding': 'br,gzip,deflate,zstd' } });
request.on('response', (response) => {
const output = fs.createWriteStream('example.com_index.html');
const onError = (err) => {
if (err) {
console.error('An error occurred:', err);
process.exitCode = 1;
}
};
switch (response.headers['content-encoding']) {
case 'br':
pipeline(response, zlib.createBrotliDecompress(), output, onError);
break;
// Or, just use zlib.createUnzip() to handle both of the following cases:
case 'gzip':
pipeline(response, zlib.createGunzip(), output, onError);
break;
case 'deflate':
pipeline(response, zlib.createInflate(), output, onError);
break;
case 'zstd':
pipeline(response, zlib.createZstdDecompress(), output, onError);
break;
default:
pipeline(response, output, onError);
break;
}
});
// Client request example
const zlib = require('node:zlib');
const http = require('node:http');
const fs = require('node:fs');
const { pipeline } = require('node:stream');
const request = http.get({ host: 'example.com',
path: '/',
port: 80,
headers: { 'Accept-Encoding': 'br,gzip,deflate,zstd' } });
request.on('response', (response) => {
const output = fs.createWriteStream('example.com_index.html');
const onError = (err) => {
if (err) {
console.error('An error occurred:', err);
process.exitCode = 1;
}
};
switch (response.headers['content-encoding']) {
case 'br':
pipeline(response, zlib.createBrotliDecompress(), output, onError);
break;
// Or, just use zlib.createUnzip() to handle both of the following cases:
case 'gzip':
pipeline(response, zlib.createGunzip(), output, onError);
break;
case 'deflate':
pipeline(response, zlib.createInflate(), output, onError);
break;
case 'zstd':
pipeline(response, zlib.createZstdDecompress(), output, onError);
break;
default:
pipeline(response, output, onError);
break;
}
});
// server example
// Running a gzip operation on every request is quite expensive.
// It would be much more efficient to cache the compressed buffer.
import zlib from 'node:zlib';
import http from 'node:http';
import fs from 'node:fs';
import { pipeline } from 'node:stream';
http.createServer((request, response) => {
const raw = fs.createReadStream('index.html');
// Store both a compressed and an uncompressed version of the resource.
response.setHeader('Vary', 'Accept-Encoding');
const acceptEncoding = request.headers['accept-encoding'] || '';
const onError = (err) => {
if (err) {
// If an error occurs, there's not much we can do because
// the server has already sent the 200 response code and
// some amount of data has already been sent to the client.
// The best we can do is terminate the response immediately
// and log the error.
response.end();
console.error('An error occurred:', err);
}
};
// Note: This is not a conformant accept-encoding parser.
// See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
if (/\bdeflate\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'deflate' });
pipeline(raw, zlib.createDeflate(), response, onError);
} else if (/\bgzip\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'gzip' });
pipeline(raw, zlib.createGzip(), response, onError);
} else if (/\bbr\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'br' });
pipeline(raw, zlib.createBrotliCompress(), response, onError);
} else if (/\bzstd\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'zstd' });
pipeline(raw, zlib.createZstdCompress(), response, onError);
} else {
response.writeHead(200, {});
pipeline(raw, response, onError);
}
}).listen(1337);
// server example
// Running a gzip operation on every request is quite expensive.
// It would be much more efficient to cache the compressed buffer.
const zlib = require('node:zlib');
const http = require('node:http');
const fs = require('node:fs');
const { pipeline } = require('node:stream');
http.createServer((request, response) => {
const raw = fs.createReadStream('index.html');
// Store both a compressed and an uncompressed version of the resource.
response.setHeader('Vary', 'Accept-Encoding');
const acceptEncoding = request.headers['accept-encoding'] || '';
const onError = (err) => {
if (err) {
// If an error occurs, there's not much we can do because
// the server has already sent the 200 response code and
// some amount of data has already been sent to the client.
// The best we can do is terminate the response immediately
// and log the error.
response.end();
console.error('An error occurred:', err);
}
};
// Note: This is not a conformant accept-encoding parser.
// See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
if (/\bdeflate\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'deflate' });
pipeline(raw, zlib.createDeflate(), response, onError);
} else if (/\bgzip\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'gzip' });
pipeline(raw, zlib.createGzip(), response, onError);
} else if (/\bbr\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'br' });
pipeline(raw, zlib.createBrotliCompress(), response, onError);
} else if (/\bzstd\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'zstd' });
pipeline(raw, zlib.createZstdCompress(), response, onError);
} else {
response.writeHead(200, {});
pipeline(raw, response, onError);
}
}).listen(1337);
By default, the zlib methods will throw an error when decompressing
truncated data. However, if it is known that the data is incomplete, or
the desire is to inspect only the beginning of a compressed file, it is
possible to suppress the default error handling by changing the flushing
method that is used to decompress the last chunk of input data:
// This is a truncated version of the buffer from the above examples
const buffer = Buffer.from('eJzT0yMA', 'base64');
zlib.unzip(
buffer,
// For Brotli, the equivalent is zlib.constants.BROTLI_OPERATION_FLUSH.
// For Zstd, the equivalent is zlib.constants.ZSTD_e_flush.
{ finishFlush: zlib.constants.Z_SYNC_FLUSH },
(err, buffer) => {
if (err) {
console.error('An error occurred:', err);
process.exitCode = 1;
}
console.log(buffer.toString());
});
This will not change the behavior in other error-throwing situations, e.g. when the input data has an invalid format. Using this method, it will not be possible to determine whether the input ended prematurely or lacks the integrity checks, making it necessary to manually check that the decompressed result is valid.
Memory usage tuning
<!--type=misc-->
For zlib-based streams
From zlib/zconf.h, modified for Node.js usage:
The memory requirements for deflate are (in bytes):
(1 << (windowBits + 2)) + (1 << (memLevel + 9));
That is: 128K for windowBits = 15 + 128K for memLevel = 8
(default values) plus a few kilobytes for small objects.
For example, to reduce the default memory requirements from 256K to 128K, the options should be set to:
const options = { windowBits: 14, memLevel: 7 };
This will, however, generally degrade compression.
The memory requirements for inflate are (in bytes) 1 << windowBits.
That is, 32K for windowBits = 15 (default value) plus a few kilobytes
for small objects.
This is in addition to a single internal output slab buffer of size
chunkSize, which defaults to 16K.
The speed of zlib compression is affected most dramatically by the
level setting. A higher level will result in better compression, but
will take longer to complete. A lower level will result in less
compression, but will be much faster.
In general, greater memory usage options will mean that Node.js has to make
fewer calls to zlib because it will be able to process more data on
each write operation. So, this is another factor that affects the
speed, at the cost of memory usage.
For Brotli-based streams
There are equivalents to the zlib options for Brotli-based streams, although these options have different ranges than the zlib ones:
- zlib's
leveloption matches Brotli'sBROTLI_PARAM_QUALITYoption. - zlib's
windowBitsoption matches Brotli'sBROTLI_PARAM_LGWINoption.
See [below][Brotli parameters] for more details on Brotli-specific options.
For Zstd-based streams
Stability: 1 - Experimental
There are equivalents to the zlib options for Zstd-based streams, although these options have different ranges than the zlib ones:
- zlib's
leveloption matches Zstd'sZSTD_c_compressionLeveloption. - zlib's
windowBitsoption matches Zstd'sZSTD_c_windowLogoption.
See [below][Zstd parameters] for more details on Zstd-specific options.
Flushing
Calling [.flush()][] on a compression stream will make zlib return as much
output as currently possible. This may come at the cost of degraded compression
quality, but can be useful when data needs to be available as soon as possible.
In the following example, flush() is used to write a compressed partial
HTTP response to the client:
import zlib from 'node:zlib';
import http from 'node:http';
import { pipeline } from 'node:stream';
http.createServer((request, response) => {
// For the sake of simplicity, the Accept-Encoding checks are omitted.
response.writeHead(200, { 'content-encoding': 'gzip' });
const output = zlib.createGzip();
let i;
pipeline(output, response, (err) => {
if (err) {
// If an error occurs, there's not much we can do because
// the server has already sent the 200 response code and
// some amount of data has already been sent to the client.
// The best we can do is terminate the response immediately
// and log the error.
clearInterval(i);
response.end();
console.error('An error occurred:', err);
}
});
i = setInterval(() => {
output.write(`The current time is ${Date()}\n`, () => {
// The data has been passed to zlib, but the compression algorithm may
// have decided to buffer the data for more efficient compression.
// Calling .flush() will make the data available as soon as the client
// is ready to receive it.
output.flush();
});
}, 1000);
}).listen(1337);
const zlib = require('node:zlib');
const http = require('node:http');
const { pipeline } = require('node:stream');
http.createServer((request, response) => {
// For the sake of simplicity, the Accept-Encoding checks are omitted.
response.writeHead(200, { 'content-encoding': 'gzip' });
const output = zlib.createGzip();
let i;
pipeline(output, response, (err) => {
if (err) {
// If an error occurs, there's not much we can do because
// the server has already sent the 200 response code and
// some amount of data has already been sent to the client.
// The best we can do is terminate the response immediately
// and log the error.
clearInterval(i);
response.end();
console.error('An error occurred:', err);
}
});
i = setInterval(() => {
output.write(`The current time is ${Date()}\n`, () => {
// The data has been passed to zlib, but the compression algorithm may
// have decided to buffer the data for more efficient compression.
// Calling .flush() will make the data available as soon as the client
// is ready to receive it.
output.flush();
});
}, 1000);
}).listen(1337);
Constants
<!-- YAML added: v0.5.8 -->
<!--type=misc-->
zlib constants
All of the constants defined in zlib.h are also defined on
require('node:zlib').constants. In the normal course of operations, it will
not be necessary to use these constants. They are documented so that their
presence is not surprising. This section is taken almost directly from the
[zlib documentation][].
Previously, the constants were available directly from require('node:zlib'),
for instance zlib.Z_NO_FLUSH. Accessing the constants directly from the module
is currently still possible but is deprecated.
Allowed flush values.
zlib.constants.Z_NO_FLUSHzlib.constants.Z_PARTIAL_FLUSHzlib.constants.Z_SYNC_FLUSHzlib.constants.Z_FULL_FLUSHzlib.constants.Z_FINISHzlib.constants.Z_BLOCK
Return codes for the compression/decompression functions. Negative values are errors, positive values are used for special but normal events.
zlib.constants.Z_OKzlib.constants.Z_STREAM_ENDzlib.constants.Z_NEED_DICTzlib.constants.Z_ERRNOzlib.constants.Z_STREAM_ERRORzlib.constants.Z_DATA_ERRORzlib.constants.Z_MEM_ERRORzlib.constants.Z_BUF_ERRORzlib.constants.Z_VERSION_ERROR
Compression levels.
zlib.constants.Z_NO_COMPRESSIONzlib.constants.Z_BEST_SPEEDzlib.constants.Z_BEST_COMPRESSIONzlib.constants.Z_DEFAULT_COMPRESSION
Compression strategy.
zlib.constants.Z_FILTEREDzlib.constants.Z_HUFFMAN_ONLYzlib.constants.Z_RLEzlib.constants.Z_FIXEDzlib.constants.Z_DEFAULT_STRATEGY
Brotli constants
<!-- YAML added: - v11.7.0 - v10.16.0 -->
There are several options and other constants available for Brotli-based streams:
Flush operations
The following values are valid flush operations for Brotli-based streams:
zlib.constants.BROTLI_OPERATION_PROCESS(default for all operations)zlib.constants.BROTLI_OPERATION_FLUSH(default when calling.flush())zlib.constants.BROTLI_OPERATION_FINISH(default for the last chunk)zlib.constants.BROTLI_OPERATION_EMIT_METADATA- This particular operation may be hard to use in a Node.js context, as the streaming layer makes it hard to know which data will end up in this frame. Also, there is currently no way to consume this data through the Node.js API.
Compressor options
There are several options that can be set on Brotli encoders, affecting
compression efficiency and speed. Both the keys and the values can be accessed
as properties of the zlib.constants object.
The most important options are:
BROTLI_PARAM_MODEBROTLI_MODE_GENERIC(default)BROTLI_MODE_TEXT, adjusted for UTF-8 textBROTLI_MODE_FONT, adjusted for WOFF 2.0 fontsBROTLI_PARAM_QUALITY- Ranges from
BROTLI_MIN_QUALITYtoBROTLI_MAX_QUALITY, with a default ofBROTLI_DEFAULT_QUALITY. BROTLI_PARAM_SIZE_HINT- Integer value representing the expected input size;
defaults to
0for an unknown input size.
The following flags can be set for advanced control over the compression algorithm and memory usage tuning:
BROTLI_PARAM_LGWIN- Ranges from
BROTLI_MIN_WINDOW_BITStoBROTLI_MAX_WINDOW_BITS, with a default ofBROTLI_DEFAULT_WINDOW, or up toBROTLI_LARGE_MAX_WINDOW_BITSif theBROTLI_PARAM_LARGE_WINDOWflag is set. BROTLI_PARAM_LGBLOCK- Ranges from
BROTLI_MIN_INPUT_BLOCK_BITStoBROTLI_MAX_INPUT_BLOCK_BITS. BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING- Boolean flag that decreases compression ratio in favour of decompression speed.
BROTLI_PARAM_LARGE_WINDOW- Boolean flag enabling “Large Window Brotli” mode (not compatible with the Brotli format as standardized in [RFC 7932][]).
BROTLI_PARAM_NPOSTFIX- Ranges from
0toBROTLI_MAX_NPOSTFIX. BROTLI_PARAM_NDIRECT- Ranges from
0to15 << NPOSTFIXin steps of1 << NPOSTFIX.
Decompressor options
These advanced options are available for controlling decompression:
BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION- Boolean flag that affects internal memory allocation patterns.
BROTLI_DECODER_PARAM_LARGE_WINDOW- Boolean flag enabling “Large Window Brotli” mode (not compatible with the Brotli format as standardized in [RFC 7932][]).
Zstd constants
Stability: 1 - Experimental
<!-- YAML added: - v23.8.0 - v22.15.0 -->
There are several options and other constants available for Zstd-based streams:
Flush operations
The following values are valid flush operations for Zstd-based streams:
zlib.constants.ZSTD_e_continue(default for all operations)zlib.constants.ZSTD_e_flush(default when calling.flush())zlib.constants.ZSTD_e_end(default for the last chunk)
Compressor options
There are several options that can be set on Zstd encoders, affecting
compression efficiency and speed. Both the keys and the values can be accessed
as properties of the zlib.constants object.
The most important options are:
ZSTD_c_compressionLevel- Set compression parameters according to pre-defined cLevel table. Default level is ZSTD_CLEVEL_DEFAULT==3.
ZSTD_c_strategy- Select the compression strategy.
- Possible values are listed in the strategy options section below.
Strategy options
The following constants can be used as values for the ZSTD_c_strategy
parameter:
zlib.constants.ZSTD_fastzlib.constants.ZSTD_dfastzlib.constants.ZSTD_greedyzlib.constants.ZSTD_lazyzlib.constants.ZSTD_lazy2zlib.constants.ZSTD_btlazy2zlib.constants.ZSTD_btoptzlib.constants.ZSTD_btultrazlib.constants.ZSTD_btultra2
Example:
const stream = zlib.createZstdCompress({
params: {
[zlib.constants.ZSTD_c_strategy]: zlib.constants.ZSTD_btultra,
},
});
Pledged Source Size
It's possible to specify the expected total size of the uncompressed input via
opts.pledgedSrcSize, which must be a non-negative safe integer. If the size
doesn't match at the end of the input, compression will fail with the code
ZSTD_error_srcSize_wrong.
[zlib.zstdCompress()][] defaults opts.pledgedSrcSize to the byte length of
its input.
Decompressor options
These advanced options are available for controlling decompression:
ZSTD_d_windowLogMax- Select a size limit (in power of 2) beyond which the streaming API will refuse to allocate memory buffer in order to protect the host from unreasonable memory requirements.
Class: Options
<!-- YAML
added: v0.11.1
changes:
- version: v26.5.0
pr-url: https://github.com/nodejs/node/pull/64023
description: The rejectGarbageAfterEnd option was added.
- version:
- v14.5.0
- v12.19.0
pr-url: https://github.com/nodejs/node/pull/33516
description: The maxOutputLength option is supported now.
- version: v9.4.0
pr-url: https://github.com/nodejs/node/pull/16042
description: The dictionary option can be an ArrayBuffer.
- version: v8.0.0
pr-url: https://github.com/nodejs/node/pull/12001
description: The dictionary option can be an Uint8Array now.
- version: v5.11.0
pr-url: https://github.com/nodejs/node/pull/6069
description: The finishFlush option is supported now.
-->
<!--type=misc-->
Each zlib-based class takes an options object. No options are required.
Some options are only relevant when compressing and are ignored by the decompression classes.
flush{integer} Default:zlib.constants.Z_NO_FLUSHfinishFlush{integer} Default:zlib.constants.Z_FINISHchunkSize{integer} Default:16 * 1024windowBits{integer}level{integer} (compression only)memLevel{integer} (compression only)strategy{integer} (compression only)dictionary{Buffer|TypedArray|DataView|ArrayBuffer} (deflate/inflate only, empty dictionary by default)info{boolean} (Iftrue, returns an object withbufferandengine.)maxOutputLength{integer} Limits output size when using [convenience methods][]. Default: [buffer.kMaxLength][]rejectGarbageAfterEnd{boolean} Iftrue, decompression fails when trailing input is detected after the end of the compressed stream. This includes unreadable bytes and, when decompressing gzip, additional gzip members following the first member. Default:false
See the [deflateInit2 and inflateInit2][] documentation for more
information.
Class: BrotliOptions
<!-- YAML
added: v11.7.0
changes:
- version: v26.5.0
pr-url: https://github.com/nodejs/node/pull/64023
description: The rejectGarbageAfterEnd option was added.
- version:
- v14.5.0
- v12.19.0
pr-url: https://github.com/nodejs/node/pull/33516
description: The maxOutputLength option is supported now.
-->
<!--type=misc-->
Each Brotli-based class takes an options object. All options are optional.
flush{integer} Default:zlib.constants.BROTLI_OPERATION_PROCESSfinishFlush{integer} Default:zlib.constants.BROTLI_OPERATION_FINISHchunkSize{integer} Default:16 * 1024params{Object} Key-value object containing indexed [Brotli parameters][].maxOutputLength{integer} Limits output size when using [convenience methods][]. Default: [buffer.kMaxLength][]info{boolean} Iftrue, returns an object withbufferandengine. Default:falserejectGarbageAfterEnd{boolean} Iftrue, decompression fails when input remains after the first complete compressed stream. Default:false
For example:
const stream = zlib.createBrotliCompress({
chunkSize: 32 * 1024,
params: {
[zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,
[zlib.constants.BROTLI_PARAM_QUALITY]: 4,
[zlib.constants.BROTLI_PARAM_SIZE_HINT]: fs.statSync(inputFile).size,
},
});
Class: zlib.BrotliCompress
<!-- YAML added: - v11.7.0 - v10.16.0 -->
- Extends: [
ZlibBase][]
Compress data using the Brotli algorithm.
Class: zlib.BrotliDecompress
<!-- YAML added: - v11.7.0 - v10.16.0 -->
- Extends: [
ZlibBase][]
Decompress data using the Brotli algorithm.
Class: zlib.Deflate
<!-- YAML added: v0.5.8 -->
- Extends: [
ZlibBase][]
Compress data using deflate.
Class: zlib.DeflateRaw
<!-- YAML added: v0.5.8 -->
- Extends: [
ZlibBase][]
Compress data using deflate, and do not append a zlib header.
Class: zlib.Gunzip
<!-- YAML
added: v0.5.8
changes:
- version: v6.0.0
pr-url: https://github.com/nodejs/node/pull/5883
description: Trailing garbage at the end of the input stream will now
result in an 'error' event.
- version: v5.9.0
pr-url: https://github.com/nodejs/node/pull/5120
description: Multiple concatenated gzip file members are supported now.
- version: v5.0.0
pr-url: https://github.com/nodejs/node/pull/2595
description: A truncated input stream will now result in an 'error' event.
-->
- Extends: [
ZlibBase][]
Decompress a gzip stream.
Class: zlib.Gzip
<!-- YAML added: v0.5.8 -->
- Extends: [
ZlibBase][]
Compress data using gzip.
Class: zlib.Inflate
<!-- YAML
added: v0.5.8
changes:
- version: v5.0.0
pr-url: https://github.com/nodejs/node/pull/2595
description: A truncated input stream will now result in an 'error' event.
-->
- Extends: [
ZlibBase][]
Decompress a deflate stream.
Class: zlib.InflateRaw
<!-- YAML
added: v0.5.8
changes:
- version: v6.8.0
pr-url: https://github.com/nodejs/node/pull/8512
description: Custom dictionaries are now supported by InflateRaw.
- version: v5.0.0
pr-url: https://github.com/nodejs/node/pull/2595
description: A truncated input stream will now result in an 'error' event.
-->
- Extends: [
ZlibBase][]
Decompress a raw deflate stream.
Class: zlib.Unzip
<!-- YAML added: v0.5.8 -->
- Extends: [
ZlibBase][]
Decompress either a Gzip- or Deflate-compressed stream by auto-detecting the header.
Class: zlib.ZipBuffer
<!-- YAML added: v26.8.0 -->
Stability: 1.0 - Early development
The ZIP archive API is experimental. Using any part of it (this class among
them) emits an experimental warning the first time; merely importing
node:zlib does not.
An in-memory, zero-copy view over the entries of a ZIP archive already
held in a Buffer, TypedArray, DataView, or ArrayBuffer. Its set of
entries can be edited - entries added or removed - but, unlike [ZipFile][],
those edits are not written into the source buffer: a newly added entry is
held as a separate in-memory [ZipEntry][] (the passed buffer is a fixed-size
view with no room to append to), and removal just drops the entry from
ZipBuffer's index. The original bytes are never modified.
[zipBuffer.toBuffer()][] serializes the current set of entries into a fresh
archive.
ZipBuffer does not copy the archive you hand it. It keeps a view onto that
memory and reads each entry's content lazily and directly from it, which is
what makes construction cheap regardless of archive size. The trade-off is
that you must not modify or reuse that memory - including the
ArrayBuffer backing a TypedArray/DataView - while the ZipBuffer, or
any [ZipEntry][] obtained from it, is still in use: a later read would
observe the change and may fail or return corrupt data. Pass a copy (for
example Buffer.from(source)) if the source might be mutated or reused.
add() and toBuffer() each have a *Sync counterpart
([addSync()][zipBuffer.addSync()], [toBufferSync()][zipBuffer.toBufferSync()])
that performs the same compression work synchronously. As with the
synchronous node:fs APIs, these block the Node.js event loop and further
JavaScript execution until the operation completes; use them only where
synchronous execution is appropriate (for example, short-lived scripts or
startup code), not in code that must stay responsive.
import { ZipBuffer } from 'node:zlib';
import { readFileSync, writeFileSync } from 'node:fs';
import { Buffer } from 'node:buffer';
const zip = new ZipBuffer(readFileSync('archive.zip'));
for (const [name, entry] of zip) {
console.log(name, entry.size);
}
await zip.add('hello.txt', Buffer.from('Hello, world!'));
zip.delete('unwanted.txt');
writeFileSync('archive.zip', await zip.toBuffer());
const { ZipBuffer } = require('node:zlib');
const { readFileSync, writeFileSync } = require('node:fs');
async function main() {
const zip = new ZipBuffer(readFileSync('archive.zip'));
for (const [name, entry] of zip) {
console.log(name, entry.size);
}
await zip.add('hello.txt', Buffer.from('Hello, world!'));
zip.delete('unwanted.txt');
writeFileSync('archive.zip', await zip.toBuffer());
}
main();
new zlib.ZipBuffer(buffer)
<!-- YAML added: v26.8.0 -->
buffer{Buffer|TypedArray|DataView|ArrayBuffer} A complete ZIP archive.
Parses the archive's central directory. Throws an [ERR_ZIP_INVALID_ARCHIVE][]
or [ERR_ZIP_UNSUPPORTED_FEATURE][] error if buffer is not a well-formed,
supported archive.
buffer is not copied: the ZipBuffer retains a zero-copy view of it (for
a TypedArray, DataView, or ArrayBuffer, of the underlying ArrayBuffer)
and reads entry content directly from it on demand. Do not mutate or reuse that
memory while the ZipBuffer or any entry read from it is still live; pass a
copy if it might change.
zipBuffer.add(filename, data[, options])
<!-- YAML added: v26.8.0 -->
filename{string} The entry's name within the archive. A trailing/marks a directory entry.data{Buffer|TypedArray|DataView|ArrayBuffer} The entry's complete, uncompressed content.options{Object} See [zlib.ZipEntry.create()][].- Returns: {Promise} Fulfilled with the created {ZipEntry}.
Equivalent to zipBuffer.addEntry(await zlib.ZipEntry.create(filename, data,
options)).
zipBuffer.addSync(filename, data[, options])
<!-- YAML added: v26.8.0 -->
filename{string} The entry's name within the archive. A trailing/marks a directory entry.data{Buffer|TypedArray|DataView|ArrayBuffer} The entry's complete, uncompressed content.options{Object} See [zlib.ZipEntry.createSync()][].- Returns: {ZipEntry} The created entry.
The synchronous version of [zipBuffer.add()][]. Equivalent to
zipBuffer.addEntry(zlib.ZipEntry.createSync(filename, data, options)).
zipBuffer.addEntry(entry)
<!-- YAML added: v26.8.0 -->
entry{ZipEntry}- Returns: {ZipEntry}
entry.
Adds an already-built entry, keyed by its own [zipEntry.name][]. Replaces
any existing entry of that name.
zipBuffer.clear()
<!-- YAML added: v26.8.0 -->
Removes every entry.
zipBuffer.comment
<!-- YAML added: v26.8.0 -->
- Type: {string}
The archive-level comment, preserved byte-for-byte across
[zipBuffer.toBuffer()][] calls unless overridden. The bytes are decoded as
UTF-8 when they are valid UTF-8 and as CP437 otherwise (the field carries no
encoding flag of its own).
zipBuffer.delete(name)
<!-- YAML added: v26.8.0 -->
name{string}- Returns: {boolean}
trueif an entry namednameexisted and was removed.
zipBuffer.entries()
<!-- YAML added: v26.8.0 -->
- Returns: {Iterator} of
[name, entry]pairs, whereentryis a [ZipEntry][].
zipBuffer.forEach(callback[, thisArg])
<!-- YAML added: v26.8.0 -->
callback{Function}thisArg{any}
Calls callback once for each entry, in the order the archive lists them.
zipBuffer.get(name)
<!-- YAML added: v26.8.0 -->
name{string}- Returns: {ZipEntry}
Throws [ERR_ZIP_ENTRY_NOT_FOUND][] if the archive has no entry named name.
zipBuffer.has(name)
<!-- YAML added: v26.8.0 -->
name{string}- Returns: {boolean}
zipBuffer.keys()
<!-- YAML added: v26.8.0 -->
- Returns: {Iterator} of entry names.
zipBuffer.size
<!-- YAML added: v26.8.0 -->
- Type: {number}
The number of entries in the archive.
zipBuffer.toBuffer([options])
<!-- YAML added: v26.8.0 -->
options{string|Object} An archive comment, as a shorthand for{ comment: options }.comment{string} An archive comment. Default: [zipBuffer.comment][].baseOffset{number} Shifts every offset the archive records by this many bytes, so the serialized archive is self-describing even when it is written somewhere other than the start of its eventual file - for example, afterbaseOffsetbytes of other content already written to the same output. Default:0.- Returns: {Promise} Fulfilled with a {Buffer} containing the serialized archive.
Serializes the current set of entries - in the order they were added or
read - into a fresh archive, switching to Zip64 structures automatically as
needed (see [zlib.createZipArchive()][]).
zipBuffer.toBufferSync([options])
<!-- YAML added: v26.8.0 -->
options{string|Object} See [zipBuffer.toBuffer()][].- Returns: {Buffer} The serialized archive.
The synchronous version of [zipBuffer.toBuffer()][] (see
[zlib.createZipArchiveSync()][]).
zipBuffer.values()
<!-- YAML added: v26.8.0 -->
- Returns: {Iterator} of [
ZipEntry][].
zipBuffer.writable
<!-- YAML added: v26.8.0 -->
- Type: {boolean}
Always true.
Class: zlib.ZipEntry
<!-- YAML added: v26.8.0 -->
Stability: 1.0 - Early development
The ZIP archive API is experimental. Using any part of it (this class among
them) emits an experimental warning the first time; merely importing
node:zlib does not.
A single file or directory inside a ZIP archive. Instances are produced by
[ZipBuffer][] and [ZipFile][], or created directly for writing with
ZipEntry.create()/ZipEntry.createStream().
create() and content() each have a *Sync counterpart (the streaming
contentIterator() does not). As with the synchronous node:fs APIs, these
block the
Node.js event loop and further JavaScript execution until the operation
(including any deflate/inflate pass) completes; use them only where
synchronous execution is appropriate (for example, short-lived scripts or
startup code), not in code that must stay responsive.
Static method: zlib.ZipEntry.create(filename, data[, options])
<!-- YAML added: v26.8.0 -->
filename{string} The entry's name within the archive. A trailing/marks a directory entry.data{Buffer|TypedArray|DataView|ArrayBuffer} The entry's complete, uncompressed content. Must be empty whenfilenamenames a directory.options{Object}comment{string} An entry comment.mode{integer} Unix permission bits. Default:0o644(0o755for directories).modified{Date} The entry's modification time. Default: the current time.method{string} One of'deflate','store', or'zstd'. Default:'deflate', except for directories and empty content, which are always stored.- Returns: {Promise} Fulfilled with a {ZipEntry}.
Compresses data (unless method is 'store', or compression would not
reduce its size) and computes its CRC-32.
When the entry ends up stored uncompressed (because method is 'store',
or because compression would not reduce the size), the entry retains a
zero-copy view of data rather than a copy, and its CRC-32 has already been
recorded. Do not mutate data after creating the entry; pass a copy if it
might change.
The MS-DOS date/time fields ZIP uses for modified have 2-second resolution
and no time zone. When modified does not fall on a whole 2-second
boundary, an Info-ZIP extended-timestamp extra field is written as well,
recording the whole (UTC) second so the time round-trips more precisely (see
[zipEntry.modified][]). This applies to every entry-creation path.
Static method: zlib.ZipEntry.createStream(filename, source[, options])
<!-- YAML added: v26.8.0 -->
filename{string} The entry's name within the archive. Must not end in/.source{AsyncIterable} Yields the entry's uncompressed content asUint8Arraychunks.options{Object}comment{string} An entry comment.mode{integer} Unix permission bits. Default:0o644.modified{Date} The entry's modification time. Default: the current time.method{string} One of'deflate','store', or'zstd'. Default:'deflate'.- Returns: {ZipEntry}
Creates an entry whose content is compressed on the fly as it is serialized
by [zlib.createZipArchive()][], without buffering source in memory. Its
size, compressedSize, and crc32 only become available once
serialization has finished. There is no synchronous counterpart: streaming
entries only make sense with an asynchronous, incrementally-produced
source.
source is drained exactly once, during serialization. Until that happens
the entry has no readable content, so [zipEntry.content()][],
[zipEntry.contentSync()][], and [zipEntry.contentIterator()][] throw
[ERR_INVALID_STATE][]. If the entry is serialized by adding it to a writable
[ZipFile][] with [zipFile.addEntry()][] (or addEntrySync()), it is then
promoted in place to a file-backed entry pointing at the copy just written,
so it becomes readable (and can be serialized again) for as long as that
ZipFile stays open. Serializing it any other way (for example directly
through [zlib.createZipArchive()][]) leaves it spent and unreadable.
Because source may hold an operating-system resource (a file read stream,
say), a streaming entry is disposable: its Symbol.dispose and
Symbol.asyncDispose methods destroy source if it has not been consumed.
An entry passed to an archive is disposed by that archive (see
[zlib.createZipArchive()][]); dispose an entry directly only when it was
built but never handed to one. Disposal is a no-op for non-streaming entries -
in particular a file-backed entry never closes the [ZipFile][] descriptor it
borrows.
Static method: zlib.ZipEntry.createSymlink(filename, target[, options])
<!-- YAML added: v26.8.0 -->
filename{string} The entry's name within the archive.target{string} The symbolic link's target path.options{Object}comment{string} An entry comment.mode{integer} Unix permission bits. Default:0o777.modified{Date} The entry's modification time. Default: the current time.- Returns: {ZipEntry}
Creates a symbolic-link entry: a stored entry whose content is target and
whose Unix mode type bits mark it as a symlink, so [zipEntry.isSymlink][] is
true when it is read back. Extraction tools that honor symlink entries
recreate the link; treat target as untrusted (see [zipEntry.name][] on
path safety).
Static method: zlib.ZipEntry.createSync(filename, data[, options])
<!-- YAML added: v26.8.0 -->
filename{string} The entry's name within the archive. A trailing/marks a directory entry.data{Buffer|TypedArray|DataView|ArrayBuffer} The entry's complete, uncompressed content. Must be empty whenfilenamenames a directory.options{Object} See [zlib.ZipEntry.create()][].- Returns: {ZipEntry}
The synchronous version of [zlib.ZipEntry.create()][].
Static method: zlib.ZipEntry.read(buffer)
<!-- YAML added: v26.8.0 -->
buffer{Buffer|TypedArray|DataView|ArrayBuffer} A complete ZIP archive.- Returns: {Iterator} of {ZipEntry}.
Parses every entry out of buffer directly, without indexing it into a
[ZipBuffer][]. Like [ZipBuffer][], the yielded entries hold zero-copy views
of buffer rather than copies of their content, so the same rule applies: do
not mutate or reuse buffer while any of them is still in use.
zipEntry.comment
<!-- YAML added: v26.8.0 -->
- Type: {string}
zipEntry.compressed
<!-- YAML added: v26.8.0 -->
- Type: {boolean}
true if the entry's content is stored in compressed form (any compression
method, currently deflate or Zstandard); false if it is stored
uncompressed.
zipEntry.compressedSize
<!-- YAML added: v26.8.0 -->
- Type: {number}
zipEntry.content([options])
<!-- YAML added: v26.8.0 -->
options{Object}verify{boolean} Verify the entry's CRC-32 checksum. Default:true.maxSize{number} Reject content declaring more than this many uncompressed bytes, before allocating anything. Default: [zlib.getMaxZipContentSize()][].- Returns: {Promise} Fulfilled with a {Buffer} containing the entry's decompressed content. The buffer is a fresh copy that shares no memory with the arch
(本文超出站点单文档体积上限,已截断)
