Sitemap

Node.Js Zlib

10 min readNov 2, 2022

--

Introduction

Imagine you have a directory of zipped files and you want to unzip them all. This can be achieved manually by clicking on all of them to unzip them, but it can also be achieved with a simple NodeJS script.

Press enter or click to view image in full size

The node:zlib module provides compression functionality implemented using Gzip, Deflate/Inflate, and Brotli. Zlib module provides a way of zip and unzip files.

How to access Zlib module?

const zlib = require('node:zlib');

Node.js Zlib : compress file

Let’s see a simple example of Node.js ZLIB module to compress a file “input.txt” into “input.txt.gz”.

const zlib = require('zlib');  
const gzip = zlib.createGzip();
const fs = require('fs');
const inp = fs.createReadStream('input.txt');
const out = fs.createWriteStream('input.txt.gz');
inp.pipe(gzip).pipe(out);

You can see that it will produce a compressed file named “input.txt.gz” on the directory.

Node.js ZLIB Example: Decompress File

Let’s see a simple example of Node.js ZLIB module to decompress a file “input.txt.gz” into “input2.txt”.

const zlib = require('zlib');    
const unzip = zlib.createUnzip();
const fs = require('fs');
const inp = fs.createReadStream('input.txt.gz');
const out = fs.createWriteStream('input2.txt');
inp.pipe(unzip).pipe(out);

Now you will see that same code of “input.txt” is available into “input2.txt” file.

Compressing HTTP requests and responses

The zlib module can be used to implement support for the gzip, deflate and br content-encoding mechanisms defined by HTTP.

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

// Client request example
const zlib = require('zlib');
const http = require('http');
const fs = require('fs');
const { pipeline } = require('stream');const request = http.get({ host: 'example.com',
path: '/',
port: 80,
headers: { 'Accept-Encoding': 'br,gzip,deflate' } });
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;
default:
pipeline(response, output, onError);
break;
}
});

server example

// 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('zlib');
const http = require('http');
const fs = require('fs');
const { pipeline } = require('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');
let acceptEncoding = request.headers['accept-encoding'];
if (!acceptEncoding) {
acceptEncoding = '';
} 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);
}
}; 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 {
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.
{ 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.

Zlib Properties and Methods

Press enter or click to view image in full size

Memory usage tuning

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 level option matches Brotli’s BROTLI_PARAM_QUALITY option.
  • zlib’s windowBits option matches Brotli’s BROTLI_PARAM_LGWIN option.

See below for more details on Brotli-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.

zlib flush() Method

The flush() method is called on a compression stream so that it can compel zlib to return as much output as achievable at present. This output may be returned at the cost of corrupt compression quality but it can be useful when data is required to be accessible as early as possible.

Syntax:

zlib.flush()

Parameters: This method does not accept any parameters.

Return Value: It returns the data as much as possible at present.

Below examples illustrate the use of zlib.flush() method in Node.js:

// Node.js program to demonstrate the
// zlib.flush() method// Including zlib module
const zlib = require('zlib');// Constructing createGzip and createGunzip
const input = zlib.createGzip();
const output = zlib.createGunzip();// Piping
input.pipe(output);// Writing to a stream of data 19000 bytes
input.write('G'.repeat(19000));// Calling flush method with callback
input.flush(() => {});// Check output
output.on('data', (d) => {
console.log('Input: Data flush with callback received '
+ d.length + ' bytes');
});
console.log("Program Complete!");

Output: So, after the byte size exceeds 16384 bytes then you need to callback flush method else data won’t be flushed fully.

zlib.createUnzip() Method

The zlib.createUnzip() method is an inbuilt application programming interface of the Zlib module which is used to create a new Unzip object.

Syntax:

zlib.createUnzip( options )

Parameters: This method accepts single parameter options which is an optional parameter that holds the zlib options.

Return Value: It returns a new Unzip object.

Below examples illustrate the use of zlib.createUnzip() method in Node.js:

// Node.js program to demonstrate the 
// createUnzip() method// Including zlib module
var zlib = require('zlib');// Calling gzip function to compress data
zlib.gzip('nodejs Zlib', function(err, data)
{
if (err)
{
return console.log('err', err);
}// Calling createUnzip method
// to decompress the data again
var unzip = zlib.createUnzip();
unzip.write(data);
unzip.on('data', function (data)
{
console.log(data.toString('hex'));
});
});

zlib.deflate() Method

The zlib.deflate() method is an inbuilt application programming interface of the Zlib module which is used to compress a chunk of data.

Get Jay Panchal’s stories in your inbox

Join Medium for free to get updates from this writer.

Syntax:

zlib.deflate( buffer, options, callback )

Parameters: This method accept three parameters as mentioned above and described below:

  • buffer: It can be of type Buffer, TypedArray, DataView, ArrayBuffer, and string.
  • options: It is an optional parameter that holds the zlib options.
  • callback: It holds the callback function.

Return Value: It returns the chunk of data after compression.

Below examples illustrate the use of zlib.deflate() method in Node.js:

// Node.js program to demonstrate the     
// deflate() method

// Including zlib module
const zlib = require("zlib");

// Declaring input and assigning
// it a value string
var input = "NodeJS Zlib";

// Calling deflate method
zlib.deflate(input, (err, buffer) => {

if (!err) {

console.log(buffer.toString('base64'));
}
else {
console.log(err);
}
});
console.log("Data Compressed...");

zlib.createDeflate() Method

The zlib.createDeflate() method is an inbuilt application programming interface of the Zlib module which is used to create a new Deflate object.

Syntax:

zlib.createDeflate( options )

Parameters: This method accepts single parameter options which is an optional parameter that holds the zlib options.

Return Value: It returns a new Deflate object.

Below examples illustrate the use of zlib.createDeflate() method in Node.js:

// Node.js program to demonstrate the 
// createDeflate() method// Including zlib and fs module
const zlib = require("zlib");
const fs = require('fs');// Creating readable Stream
const inp = fs.createReadStream('input.txt');// Creating writable stream
const out = fs.createWriteStream('input.txt.gz');// Calling createDeflate method
const def = zlib.createDeflate();// Piping
inp.pipe(def).pipe(out);
console.log("Program Completed!");

zlib.deflateSync() Method

The zlib.deflateSync() method is an inbuilt application programming interface of the Zlib module which is used to compresses a chunk of data with Deflate.

Syntax:

zlib.deflateSync( buffer, options )

Parameters: This method accepts two parameters as mentioned above and described below:

  • buffer: This parameter holds the buffer of type Buffer, TypedArray, DataView, ArrayBuffer, string.
  • options: This parameter holds the zlib options value.

Return Value: It returns the chunk of data with deflate.

Below examples illustrate the use of zlib.deflateSync() method in Node.js:

// Node.js program to demonstrate the 
// zlib.deflateSync() method// Including zlib module
var zlib = require('zlib');// Declaring input and assigning
// it a value string
var input = "AWT Article";// Calling deflateSync method and converting
// the deflate to string encoded with hex
var deflated = zlib.deflateSync(input).toString('hex');console.log(deflated);

zlib.inflate() Method

The zlib.inflate() method is an inbuilt application programming interface of the Zlib module which is used to decompress a chunk of data.

Syntax:

zlib.inflate( buffer, options, callback )

Parameters: This method accepts three parameters as mentioned above and described below:

  • buffer: It can be of type Buffer, TypedArray, DataView, ArrayBuffer, and string.
  • options: It is an optional parameter that holds the zlib options.
  • callback: It holds the callback function.

Return Value: It returns the chunk of data after decompression.

Below examples illustrate the use of zlib.inflate() method in Node.js:

// Node.js program to demonstrate the     
// inflate() method

// Including zlib module
const zlib = require("zlib");

// Declaring input and assigning
// it a value string
var input = "ZLib NodeJS";

// Calling deflate method
zlib.deflate(input, (err, buffer) => {

// Calling inflate method
zlib.inflate(buffer, (err, buffer) => {
console.log(buffer.toString('utf8'));
});
});

zlib.createInflate() Method

The zlib.createInflate() method is an inbuilt application programming interface of the Zlib module which is used to create a new Inflate object.

Syntax:

zlib.createInflate( options )

Parameters: This method accepts single parameter options which is an optional parameter that holds the zlib options.

Return Value: It returns a new Inflate object.

Below example illustrate the use of zlib.createInflate() method in Node.js:

// Node.js program to demonstrate the 
// createInflate() method// Including zlib module
var zlib = require('zlib');// Calling deflate function to compress data
zlib.deflate('Decompressed..', function(err, data)
{
if (err)
{
return console.log('err', err);
}// Calling createInflate method
// to decompress the data again
var gunzip = zlib.createInflate();
gunzip.write(data);
gunzip.on('data', function (data)
{
console.log(data.toString('hex'));
});
});

zlib.inflateSync() Method

The zlib.inflateSync() method is an inbuilt application programming interface of the Zlib module which is used to decompress a chunk of data with Inflate.

Syntax:

zlib.inflateSync( buffer, options )

Parameters: This method accepts two parameters as mentioned above and described below:

  • buffer: This parameter holds the buffer of type Buffer, TypedArray, DataView, ArrayBuffer, string.
  • options: This parameter holds the zlib options value.

Return Value: It returns the chunk of data with Inflate.

Below examples illustrate the use of zlib.inflateSync() method in Node.js:

// Node.js program to demonstrate the 
// zlib.inflateSync() method// Including zlib module
var zlib = require('zlib');// Declaring input and assigning
// it a value string
var input = "zlib module";// Calling deflateSync method
var deflated = zlib.deflateSync(input).toString('hex');// Calling inflateSync method
var inflated = zlib.inflateSync(new Buffer.from(
deflated, 'hex')).toString('base64');console.log(inflated);

Hope this article helped you. Let us know if you have any doubts and suggestions.

our team members

20CE035 HITEN JADAV

20CE037 RIP JAKHARIA

20CE047 BRIJESH LADVA

20CE053 SMIT MATALIYA

20CE068 JAY PANCHAL

--

--