Zlib
Модуль zlib предоставляет функциональность сжатия, реализованную с использованием Gzip и Deflate/Inflate. К нему можно обратиться, используя:
const zlib = require('zlib');
Сжатие или распаковку потока (например, файла) можно выполнить, передав данные исходного потока через 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);
Также возможно сжать или распаковать данные в одном шаге:
const input = '.................................';
zlib.deflate(input, (err, buffer) => {
if (!err) {
console.log(buffer.toString('base64'));
} else {
// handle error
}
});
const buffer = Buffer.from('eJzT0yMAAGTvBe8=', 'base64');
zlib.unzip(buffer, (err, buffer) => {
if (!err) {
console.log(buffer.toString());
} else {
// handle error
}
});
Сжатие HTTP-запросов и ответов
Модуль zlib может использоваться для реализации поддержки механизмов кодирования содержимого gzip и deflate, определённых в HTTP.
Заголовок HTTP Accept-Encoding используется в запросе HTTP для идентификации кодировок сжатия, поддерживаемых клиентом. Заголовок Content-Encoding используется для идентификации фактически применённых кодировок сжатия к сообщению.
Примечание: приведённые ниже примеры сильно упрощены, чтобы показать базовый принцип. Использование кодирования zlib может быть дорогостоящим, и результаты следует кэшировать. Подробнее о компромиссах между скоростью, памятью и сжатием при использовании zlib см. в разделе Настройка использования памяти.
// client request example
const zlib = require('zlib');
const http = require('http');
const fs = require('fs');
const request = http.get({ host: 'example.com',
path: '/',
port: 80,
headers: { 'Accept-Encoding': 'gzip,deflate' } });
request.on('response', (response) => {
const output = fs.createWriteStream('example.com_index.html');
switch (response.headers['content-encoding']) {
// or, just use zlib.createUnzip() to handle both cases
case 'gzip':
response.pipe(zlib.createGunzip()).pipe(output);
break;
case 'deflate':
response.pipe(zlib.createInflate()).pipe(output);
break;
default:
response.pipe(output);
break;
}
});
// 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');
http.createServer((request, response) => {
const raw = fs.createReadStream('index.html');
let acceptEncoding = request.headers['accept-encoding'];
if (!acceptEncoding) {
acceptEncoding = '';
}
// Note: this is not a conformant accept-encoding parser.
// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
if (acceptEncoding.match(/\bdeflate\b/)) {
response.writeHead(200, { 'Content-Encoding': 'deflate' });
raw.pipe(zlib.createDeflate()).pipe(response);
} else if (acceptEncoding.match(/\bgzip\b/)) {
response.writeHead(200, { 'Content-Encoding': 'gzip' });
raw.pipe(zlib.createGzip()).pipe(response);
} else {
response.writeHead(200, {});
raw.pipe(response);
}
}).listen(1337);
По умолчанию методы zlib будут генерировать ошибку при распаковке усечённых данных. Однако, если известно, что данные неполные, или требуется просмотреть только начало сжатого файла, можно подавить обработку по умолчанию, изменив метод сброса, используемый для сжатия последней части входных данных:
// This is a truncated version of the buffer from the above examples
const buffer = Buffer.from('eJzT0yMA', 'base64');
zlib.unzip(
buffer,
{ finishFlush: zlib.Z_SYNC_FLUSH },
(err, buffer) => {
if (!err) {
console.log(buffer.toString());
} else {
// handle error
}
});
Это не изменит поведение в других ситуациях, генерирующих ошибки, например, когда входные данные имеют неверный формат. Использование этого метода не позволит определить, закончился ли входной поток преждевременно или не имеет проверок целостности, поэтому необходимо вручную проверить, что результат распаковки корректен.
Настройка использования памяти
Из zlib/zconf.h, изменённое для использования в Node.js:
Требования к памяти для deflate (в байтах):
(1 << (windowBits + 2)) + (1 << (memLevel + 9));
То есть: 128 КБ для windowBits = 15 + 128 КБ для memLevel = 8 (значения по умолчанию) плюс несколько килобайт для небольших объектов.
Например, чтобы уменьшить значения по умолчанию с 256 КБ до 128 КБ, нужно установить:
const options = { windowBits: 14, memLevel: 7 };
Однако это, как правило, ухудшит сжатие.
Требования к памяти для inflate (в байтах):
1 << windowBits;
То есть 32 КБ для windowBits = 15 (значение по умолчанию) плюс несколько килобайт для небольших объектов.
Кроме того, используется один внутренний буфер выходного набора размером chunkSize, по умолчанию равный 16 КБ.
Скорость сжатия zlib в наибольшей степени зависит от параметра level. Более высокое значение обеспечивает лучшее сжатие, но занимает больше времени. Более низкое значение приводит к меньшему сжатию, но выполняется быстрее.
В целом, большие значения параметров использования памяти означают, что Node.js будет выполнять меньше вызовов zlib, так как сможет обрабатывать больше данных в каждом write операции. Поэтому это ещё один фактор, влияющий на скорость, но за счёт использования больше памяти.
Сброс
Вызов .flush() в потоке сжатия заставит zlib вернуть как можно больше выходных данных в данный момент. Это может привести к ухудшению качества сжатия, но может быть полезно, когда данные необходимо получить как можно быстрее.
В следующем примере используется flush() для записи сжатого частичного HTTP-ответа клиенту:
const zlib = require('zlib');
const http = require('http');
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();
output.pipe(response);
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);
Константы
Все константы, определённые в zlib.h, также определены в require('zlib'). В обычном режиме работы нет необходимости использовать эти константы. Они задокументированы, чтобы их присутствие не вызывало удивления. Этот раздел взят практически напрямую из документации zlib. Подробнее см. http://zlib.net/manual.html#Constants.
Разрешённые значения сброса.
zlib.Z_NO_FLUSHzlib.Z_PARTIAL_FLUSHzlib.Z_SYNC_FLUSHzlib.Z_FULL_FLUSHzlib.Z_FINISHzlib.Z_BLOCKzlib.Z_TREES
Коды возврата для функций сжатия/распаковки. Отрицательные значения — ошибки, положительные значения используются для особых, но нормальных событий.
zlib.Z_OKzlib.Z_STREAM_ENDzlib.Z_NEED_DICTzlib.Z_ERRNOzlib.Z_STREAM_ERRORzlib.Z_DATA_ERRORzlib.Z_MEM_ERRORzlib.Z_BUF_ERRORzlib.Z_VERSION_ERROR
Уровни сжатия.
zlib.Z_NO_COMPRESSIONzlib.Z_BEST_SPEEDzlib.Z_BEST_COMPRESSIONzlib.Z_DEFAULT_COMPRESSION
Стратегия сжатия.
zlib.Z_FILTEREDzlib.Z_HUFFMAN_ONLYzlib.Z_RLEzlib.Z_FIXEDzlib.Z_DEFAULT_STRATEGY
Метод сжатия deflate (единственный поддерживаемый в этой версии).
zlib.Z_DEFLATED
Для инициализации zalloc, zfree, opaque.
zlib.Z_NULL
Параметры класса
Каждый класс принимает объект options. Все параметры необязательны.
Обратите внимание, что некоторые параметры актуальны только при сжатии и игнорируются классами распаковки.
-
flush(по умолчанию:zlib.Z_NO_FLUSH) -
finishFlush(по умолчанию:zlib.Z_FINISH) -
chunkSize(по умолчанию:16 * 1024) windowBits-
level(только для сжатия) -
memLevel(только для сжатия) -
strategy(только для сжатия) -
dictionary(только для deflate/inflate, пустой словарь по умолчанию)
См. описание deflateInit2 и inflateInit2 на http://zlib.net/manual.html#Advanced для получения дополнительной информации.
Класс: zlib.Deflate
Сжатие данных с использованием deflate.
Класс: zlib.DeflateRaw
Сжатие данных с использованием deflate без добавления заголовка zlib.
Класс: zlib.Gunzip
Распаковка gzip-потока.
Класс: zlib.Gzip
Сжатие данных с использованием gzip.
Класс: zlib.Inflate
Распаковка deflate-потока.
Класс: zlib.InflateRaw
Распаковка потока raw deflate.
Класс: zlib.Unzip
Распаковка потока, сжатого с помощью Gzip или Deflate, автоматически определяя заголовок.
Класс: zlib.Zlib
Не экспортируется модулем zlib. Он документирован здесь, потому что является базовым классом для классов сжатия/распаковки.
zlib.close([callback])
Закрытие внутреннего дескриптора.
zlib.flush([kind], callback)
kind по умолчанию zlib.Z_FULL_FLUSH.
Сброс ожидающих данных. Не вызывайте это слишком часто, преждевременный сброс отрицательно влияет на эффективность алгоритма сжатия.
Этот вызов только сбрасывает данные из внутреннего состояния zlib, и не выполняет сброс на уровне потоков. Скорее, он ведёт себя как обычный вызов .write(), т. е. он будет помещён в очередь позади других ожидающих записей и произведёт вывод только при чтении данных из потока.
zlib.params(level, strategy, callback)
Динамическое обновление уровня сжатия и стратегии сжатия. Применимо только к алгоритму deflate.
zlib.reset()
Сброс сжимателя/распаковщика до заводских настроек. Применимо только к алгоритмам inflate и deflate.
zlib.constants
Предоставляет объект, перечисляющий константы, связанные с Zlib.
zlib.createDeflate(options)
Возвращает новый объект Deflate с параметрами options.
zlib.createDeflateRaw(options)
Возвращает новый объект DeflateRaw с параметрами options.
Примечание: Обновление zlib с 1.2.8 до 1.2.11 изменило поведение при установке windowBits в 8 для потоков raw deflate. zlib автоматически устанавливал windowBits в 9, если он изначально был равен 8. Более новые версии zlib будут генерировать исключение, поэтому Node.js восстановил исходное поведение, повышая значение 8 до 9, так как передача windowBits = 9 в zlib фактически приводит к потоку сжатия, который эффективно использует 8-битный окно только.
zlib.createGunzip(options)
Возвращает новый объект Gunzip с параметрами options.
zlib.createGzip(options)
Возвращает новый объект Gzip с параметрами options.
zlib.createInflate(options)
Возвращает новый объект Inflate с параметрами options.
zlib.createInflateRaw(options)
Возвращает новый объект InflateRaw с параметрами options.
zlib.createUnzip(options)
Возвращает новый объект Unzip с параметрами options.
Удобные методы
Все они принимают Buffer или строку в качестве первого аргумента, необязательный второй аргумент для задания параметров для классов zlib и вызовут предоставленную функцию обратного вызова с callback(error, result).
Каждый метод имеет *Sync аналог, который принимает те же аргументы, но без обратного вызова.
zlib.deflate(buf[, options], callback)
zlib.deflateSync(buf[, options])
Сжимает Buffer или строку с помощью Deflate.
zlib.deflateRaw(buf[, options], callback)
zlib.deflateRawSync(buf[, options])
Сжимает Buffer или строку с помощью DeflateRaw.
zlib.gunzip(buf[, options], callback)
zlib.gunzipSync(buf[, options])
Распаковывает Buffer или строку с помощью Gunzip.
zlib.gzip(buf[, options], callback)
zlib.gzipSync(buf[, options])
Сжимает Buffer или строку с помощью Gzip.
zlib.inflate(buf[, options], callback)
zlib.inflateSync(buf[, options])
Распаковывает Buffer или строку с помощью Inflate.
zlib.inflateRaw(buf[, options], callback)
zlib.inflateRawSync(buf[, options])
Распаковывает Buffer или строку с помощью InflateRaw.
zlib.unzip(buf[, options], callback)
zlib.unzipSync(buf[, options])
Распаковывает Buffer или строку с помощью Unzip.
© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v6.x/docs/api/zlib.html