node:zlib 模块提供了使用 Gzip、Deflate/Inflate、以及 Brotli 实现的压缩功能。
deflate 算法
DEFLATE是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法。DEFLATE压缩与解代码可以在自由、通用的压缩库zlib上找到。常见的压缩算法如下:
- zlib(RFC1950):一种格式,是对deflate进行了简单的封装,zlib = zlib头 + deflate编码的实际内容 + zlib尾
- gzip(RFC1952):一种格式,也是对deflate进行的封装,gzip = gzip头 + deflate编码的实际内容 + gzip尾
LZ77算法
LZ77是一种基于字典的算法,它将长字符串(也称为短语)编码成短小的标记,用小标记代替字典中的短语,从而达到压缩的目的。也就是说,它通过用小的标记来代替数据中多次重复出现的长串方法来压缩数据。其处理的符号不一定是文本字符,可以是任意大小的符号。
使用
压缩
const { createGzip } = require('zlib');
const { pipeline } = require('stream');
const {
createReadStream,
createWriteStream
} = require('fs');
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;
}
});
// 或者,promise 化
const { promisify } = require('util');
const pipe = promisify(pipeline);
async function do_gzip(input, output) {
const gzip = createGzip();
const source = createReadStream(input);
const destination = createWriteStream(output);
await pipe(source, gzip, destination);
}
do_gzip('input.txt', 'input.txt.gz')
.catch((err) => {
console.error('An error occurred:', err);
process.exitCode = 1;
});
解压
const { createGunzip } = require('zlib');
const { pipeline } = require('stream');
const {
createReadStream,
createWriteStream
} = require('fs');
const gzip = createGunzip();
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;
}
});
Zlib属性和方法
Method | Description |
---|---|
constants | Returns an object containing Zlib constants |
createDeflate() | Creates a Deflate object |
createDeflateRaw() | Creates a DeflateRaw object |
createGunzip() | Creates a Gunzip object |
createGzip() | Creates a Gzip object |
createInflate() | Creates a Inflate object |
createInflateRaw() | Creates a InflateRaw object |
createUnzip() | Creates a Unzip object |
deflate() | Compress a string or buffer, using Deflate |
deflateSync() | Compress a string or buffer, syncronously, using Deflate |
deflateRaw() | Compress a string or buffer, using DeflateRaw |
deflateRawSync() | Compress a string or buffer, syncronously, using DeflateRaw |
gunzip() | Compress a string or buffer, using Gunzip |
gunzipSync() | Compress a string or buffer, syncronously, using Gunzip |
gzip() | Compress a string or buffer, using Gzip |
gzipSync() | Compress a string or buffer, syncronously, using Gzip |
inflate() | Decompress a string or buffer, using Inflate |
inflateSync() | Decompress a string or buffer, syncronously, using Inflate |
inflateRaw() | Decompress a string or buffer, using InflateRaw |
inflateRawSync() | Decompress a string or buffer, syncronously, using InflateRaw |
unzip() | Decompress a string or buffer, using Unzip |
unzipSync() | Decompress a string or buffer, syncronously, using Unzip |
内存使用的调整
对于基于 zlib 的流
从 zlib/zconf.h 开始,针对 Node.js 使用进行了修改:
deflate 的内存要求是(以字节为单位):
(1 << (windowBits + 2)) + (1 << (memLevel + 9))
即:windowBits 的 128K = 15 + memLevel 的 128K = 8(默认值)加上小对象的几千字节。
例如,要将默认内存要求从 256K 减少到 128K,应将选项设置为:
const options = { windowBits: 14, memLevel: 7 };
然而,这通常会降低压缩性能。
inflate 的内存要求是(以字节为单位)1 << windowBits。 也就是说,windowBits 的 32K = 15(默认值)加上小对象的几千字节。
这是对大小为 chunkSize 的单个内部输出平板缓冲区的补充,默认为 16K。
zlib 压缩的速度受 level 设置的影响最大。 更高的级别将导致更好的压缩,但需要更长的时间才能完成。 较低的级别将导致较少的压缩,但会更快。
一般来说,更大的内存使用选项意味着 Node.js 必须对 zlib 进行更少的调用,因为它能够在每个 write 操作上处理更多的数据。 所以,这是影响速度的另一个因素,以内存使用为代价。