الوحدة Zlib في Node.js

من موسوعة حسوب

مؤشر الاستقرار: 2 - مستقر

توفر الوحدة 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 {
    // معالجة الخطأ
  }
});

const buffer = Buffer.from('eJzT0yMAAGTvBe8=', 'base64');
zlib.unzip(buffer, (err, buffer) => {
  if (!err) {
    console.log(buffer.toString());
  } else {
    // معالجة الخطأ
  }
});

استخدام مُجمّع الخيوط

لاحظ أن كافة واجهات برمجة تطبيقات zlib باستثناء تلك التي تكون متزامنة بشكل صريح تستخدم مُجمّع خيوط libuv. ويمكن أن يؤدي هذا إلى تأثيرات مفاجئة في بعض التطبيقات، مثل الأداء المتدني (والذي يمكن التخفيف منه عن طريق ضبط حجم المُجمّع) و/أو تقسيم الذاكرة غير القابل للاسترداد الكارثي.

ضغط طلبات واستجابات HTTP

يمكن استخدام الوحدة zlib لتنفيذ دعم أليات ترميز المحتوي gzip و deflate المُعرَّفة من قِبَل HTTP.

تستخدم ترويسة قبول الترميز Accept-Encoding  الخاصة HTTP ضمن طلب http لتعريف ترميزات الضغط المقبولة من قبل العميل. وتستخدم ترويسة ترميز المحتوي Content-Encoding  لتعريف ترميزات الضغط المُطبَّقة فعليًا علي رسالةٍ ما.

توضح الأمثلة التالية المفهوم الأساسي بشكل مبسط للغاية. يمكن أن يكون استخدام ترميز zlib مُكلفًا، ويجب أن تُخزَّن النتائج مؤقتًا. راجع قسم ضبط استخدام الذاكرة للحصول على مزيد من المعلومات حول المفاضلات بين السرعة والذاكرة والضغط المتضمنين في استخدام zlib.

// مثال على طلب العميل
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']) {
    // أو, استخدم فقط zlib.createUnzip() لمعالجة الحالتين
    case 'gzip':
      response.pipe(zlib.createGunzip()).pipe(output);
      break;
    case 'deflate':
      response.pipe(zlib.createInflate()).pipe(output);
      break;
    default:
      response.pipe(output);
      break;
  }
});

افتراضيًا، تُطلق توابع zlib خطأً عند فك ضغط البيانات المبتورة. ومع ذلك، إذا كان من المعروف أن البيانات غير كاملة، أو كانت الرغبة في فحص بداية الملف المضغوط فقط، فمن الممكن منع معالجة الخطأ الافتراضي بواسطة تغيير تابع التدفق المستخدم لفك ضغط الجزء الأخير من البيانات المُدخَلة:

// هذه نسخة مبتورة من المخزن المؤقت من الأمثلة المذكورة أعلاه
const buffer = Buffer.from('eJzT0yMA', 'base64');

zlib.unzip(
  buffer,
  { finishFlush: zlib.constants.Z_SYNC_FLUSH },
  (err, buffer) => {
    if (!err) {
      console.log(buffer.toString());
    } else {
      // معالجة الخطأ
    }
  });

لن يؤدي ذلك إلى تغيير السلوك في حالات إطلاق الأخطاء الأخرى، علي سبيل المثال عندما يكون تنسيق البيانات المُدخَلة غير صالح. فباستخدام هذا التابع، لن يكون من الممكن تحديد ما إذا كان الإدخال قد انتهي قبل الأوان أم انه يفتقر إلى فحوص التكامل، مما يجعل من الضروري التحقق يدويًا من صحة النتيجة التي فُكَّ ضغطها.

ضبط استخدام الذاكرة

من zlib/zlib.h، مُعدَّلة إلى استخدام Node js:

متطلبات الذاكرة للانكماش هي (بالبايت):

(1 << (windowBits + 2)) + (1 << (memLevel + 9))

أي: 128K لـ windowBits = 15‎‎ + 128K لـ memLevel = 8 (القيم الافتراضية) بالإضافة إلى عدد قليل من الكيلوبايت للكائنات الصغيرة. علي سبيل المثال، لتقليل متطلبات الذاكرة الافتراضية من 256K إلى 128K، يجب ضبط الخيارات إلى:

const options = { windowBits: 14, memLevel: 7 };

ومع ذلك، سيؤدي هذا إلى انخفاض مقدار الضغط بشكل عام.

متطلبات الذاكرة للتضخيم هي (بالبايت) ‎1 << windowBits. أي، 32K لـ windowBits = 15 (القيمة الافتراضية) بالإضافة إلى عدد قليل من الكيلوبايت للكائنات الصغيرة.

هذا بالإضافة إلى شريحة المخزن المؤقت الوحيد للإخراج الداخلي والتي يكون حجمها chunkSize، ذات القيمة الافتراضية 16K.

تتأثر سرعة ضغط zlib بشكل كبير بإعداد المستوى. سيؤدي مستوي أعلي إلى ضغط أفضل، ولكن سيستغرق وقتًا أطول لإكماله. بينما سيؤدي مستوى أقل إلى ضغطٍ أقل، ولكن سيكون أسرع بكثير.

بشكل عام ستعني خيارات استخدام ذاكرة أكبر أن على Node.js إجراء استدعاءات أقل إلى zlib لأنها ستكون قادرة علي معالجة المزيد من البيانات عند كل عملية كتابة. لذا، سيكون هذا عاملًا آخر يؤثر على السرعة، على حساب استخدام الذاكرة.

التدفق (Flushing)

سيؤدي استدعاء ‎.flush()‎ علي دفق الضغط لأن يُعيد zlib المُخرَج بقدر الإمكان حاليًا. وقد يأتي ذلك على حساب جودة الضغط المتدهورة، ولكن قد يكون ذلك مفيدًا عند الحاجة لأن تكون البيانات متاحة في أقرب وقت ممكن.

في المثال التالي ، يُستخدم flush()‎ التابع لكتابة استجابة HTTP جزئية مضغوطة إلى العميل:

const zlib = require('zlib');
const http = require('http');

http.createServer((request, response) => {
  // من أجل التبسيط، حُذفت الفحوص الخاصة بـ Accept-Encoding.
  response.writeHead(200, { 'content-encoding': 'gzip' });
  const output = zlib.createGzip();
  output.pipe(response);

  setInterval(() => {
    output.write(`The current time is ${Date()}\n`, () => {
      // مٌررت البيانات إلى zlib، ولكن قد تقرر خوارزمية الضغط
      // تخزين البيانات مؤقتًا للحصول على ضغط أكثر فعالية.
      // سيجعل استدعاء .flush() البيانات متاحة بمجرد
      // أن يكون العميل جاهزًا لتلقيها.
      output.flush();
    });
  }, 1000);
}).listen(1337);

الثوابت (Constants)

أُضيف مع الإصدار: v0.5.8.

جميع الثوابت المُعرَّفة في zlib.h تكون مُعرَّفة أيضًا في require('zlib').constants. في المسار العادي للعمليات، لن يكون من الضروري استخدام هذه الثوابت. وهي موثقة بحيث لا يكون وجودها مفاجئًا. هذا المقطع مأخوذ تقريبًا مباشرةً من وثائق zlib. راجع https://zlib.net/manual.htmlConstants لمزيد من التفاصيل.

في السابق، كانت الثوابت متوفرة مباشرة من require('zlib')‎، على سبيل المثال zlib.Z_NO_FLUSH. لا يزال الوصول إلى الثوابت مباشرة من الوحدة ممكنًا حاليًا ولكنه مهمل.

قيم التدفق flush المسموح بها.

  • zlib.constants.Z_NO_FLUSH
  • zlib.constants.Z_PARTIAL_FLUSH
  • zlib.constants.Z_SYNC_FLUSH
  • zlib.constants.Z_FULL_FLUSH
  • zlib.constants.Z_FINISH
  • zlib.constants.Z_BLOCK
  • zlib.constants.Z_TREES

الرموز المُعادة لدوال الضغط وفك الضغط. القيم السالبة أخطاء، وتستخدم القيم الموجبة للأحداث الخاصة ولكن العادية.

  • zlib.constants.Z_OK
  • zlib.constants.Z_STREAM_END
  • zlib.constants.Z_NEED_DICT
  • zlib.constants.Z_ERRNO
  • zlib.constants.Z_STREAM_ERROR
  • zlib.constants.Z_DATA_ERROR
  • zlib.constants.Z_MEM_ERROR
  • zlib.constants.Z_BUF_ERROR
  • zlib.constants.Z_VERSION_ERROR

مستويات الضغط.

  • zlib.constants.Z_NO_COMPRESSION
  • zlib.constants.Z_BEST_SPEED
  • zlib.constants.Z_BEST_COMPRESSION
  • zlib.constants.Z_DEFAULT_COMPRESSION

استراتيجية الضغط.

  • zlib.constants.Z_FILTERED
  • zlib.constants.Z_HUFFMAN_ONLY
  • zlib.constants.Z_RLE
  • zlib.constants.Z_FIXED
  • zlib.constants.Z_DEFAULT_STRATEGY

الصنف Options

سجل التغييرات

الإصدار التغييرات
v9.4.0 يمكن أن يكون الخيار dictionary من النوع ArrayBuffer.
v8.0.0 يمكن أن يكون الخيار dictionary من النوع Uint8Array.
v5.11.0 بداية دعم finishFlush .
v0.11.1 أُضيف مع الإصدار: v0.11.1

يأخذ كل صنف كائن options. جميع الخيارات اختيارية.

لاحظ أن بعض الخيارات تكون متاحة فقط عند الضغط، وتُتجاهل من أصناف فك الضغط.

  •  flush من النوع <integer>، القيمة الافتراضية: zlib.constants.Z_NO_FLUSH.
  •  finishFlush من النوع <integer>، القيمة الافتراضية: zlib.constants.Z_FINISH.
  •  chunksize من النوع <integer> القيمة الافتراضية: ‎16 * 1024.
  •  windowbits من النوع<integer>.
  •  level من النوع <integer> (الضغط فقط).
  •  memLevel من النوع <integer> (الضغط فقط).
  •  strategy من النوع <integer> (الضغط فقط).
  •  dictionary من النوع ‎<Buffer> | <TypedArray> | <DataView> | <ArrayBuffer>‎ (الانكماش/التضخيم فقط، قاموس فارغ بشكل افتراضي).
  • info من النوع <boolean> (إذا كان true، يعيد كائن مع buffer و engine).

راجع وصف deflateinit2 و inflateinit2 على الرابط https://zlib.net/manual.htmlAdvanced للحصول علي مزيد من المعلومات.

الصنف zlib.Deflate

أُضيف مع الإصدار: v0.5.8.

ضغط البيانات باستخدام deflate.

الصنف zlib.DeflateRaw

أُضيف مع الإصدار: v0.5.8.

ضغط البيانات باستخدام deflate، وعدم إلحاق ترويسة zlib.

الصنف zlib.Gunzip

سجل التغييرات

الإصدار التغييرات
v6.0.0 ستؤدي المُهملات الخلفية في نهاية دفق الإدخال الآن إلى إنطلاق حدث 'error'.
v5.9.0 بداية دعم أعضاء ملف gzip متسلسلة متعددة .
v5.0.0 سيؤدي الآن تدفق مبتور إلى إنطلاق حدث  'error'.
v0.5.8 أُضيف مع الإصدار: v0.5.8.

فك ضغط تيار gzip.

الصنف zlib.Gzip

أُضيف مع الإصدار: v0.5.8.

ضغط البيانات باستخدام gzip.

الصنف zlib.Inflate

سجل التغييرات

الإصدار التغييرات
v5.0.0 سيؤدي الآن تدفق مبتور إلى إنطلاق حدث  'error'.
v0.5.8 أُضيف مع الإصدار: v0.5.8.

فك ضغط تيار انكماش.

الصنف: zlib.InflateRaw [المصدر]

سجل التغييرات

الإصدار التغييرات
v6.8.0 بداية دعم القواميس المخصصة بواسطة InflateRaw.
v5.0.0 سيؤدي الآن تدفق مبتور إلى إنطلاق حدث  'error'.
v0.5.8 أُضيف مع الإصدار: v0.5.8.

فك ضغط تيار انكماش خام.

الصنف zlib.Unzip

أُضيف مع الإصدار: v0.5.8.

فك ضغط دفق Gzip-‎ أو Deflate-‎ المضغوط بالكشف التلقائي عن الترويسة.

الصنف zlib.Zlib

أُضيف مع الإصدار: v0.5.8.

لا تُصدَّر بواسطة الوحدة zlib. وهو موثق هنا لأنه هو الصنف الأساسي من أصناف الضواغط/وفاكّي الضغط.

يرث هذا الصنف من stream.Transform، سامحًا لكائنات zlib بأن تُستخدم في الأنابيب وعمليات الدفق المماثلة.

zlib. bytesRead

أُضيف مع الإصدار: v8.1.0، وأُهمِل مع الإصدار: v10.0.0.

مؤشر الاستقرار: 0 - مُهمَل: يُستخدم zlib.bytesWritten بدلًا منه.

اسم مستعار مُهمل للخاصية zlib.bytesWritten. اُختير هذا الاسم المبتكر لأنه من المنطقي أيضا تفسير القيمة بعدد البايتات المقروءة بواسطة المُحرك، ولكنه غير متناسق مع التدفقات الأخرى في Node.js التي تعرض القيم تحت هذه الأسماء.

zlib.bytesWritten

أُضيفت مع الإصدار: v10.0.0.

تحدد الخاصية zlib.bytesWritten عدد وحدات البايت المكتوبة إلى المُحرِّك قبل معالجة وحدات البايت (مضغوطة أو غير مضغوطة، بما يتناسب مع الصنف المشتق).

zlib.close([callback])‎

أُضيف مع الإصدار: v0.9.4.

اغلاق المُعالج الأساسي.

zlib.flush([kind, ]callback)‎

أُضيف مع الإصدار: v0.5.8.

  •  kind القيمة الافتراضية: zlib.constants.Z_FULL_FLUSH.

تدفق البيانات المُعلَّقة. على عكس ما يبدو، يؤثر التدفق المبكر سلبًا على فاعلية خوارزمية الضغط.

استدعاء هذا التابع يدفع البيانات من الحالة zlib الداخلية، ولا يدفع أي نوع علي مستوي التدفقات. وبدلًا من ذلك، فإنه يتصرف مثل استدعاءٍ عادي للتابع ‎.write()‎، أي أنه سيُضاف إلى قائمة الانتظار وراء الكتابات الأخرى المعلقة وسينتج مُخرجات فقط عند قراءة البيانات من الدفق.

zlib.params(level, strategy, callback)‎

أُضيف مع الإصدار: v0.11.4.

تحديث مستوى الضغط واستراتيجية الضغط بشكل حيوي. ينطبق فقط على خوارزمية الانكماش.

zlib.reset()‎

أُضيف مع الإصدار: v0.7.0.

أعاده تعيين الضاغط/إلغاء ضغط إلى إعدادات المصنع الافتراضية. تنطبق فقط على خوارزميات inflate و deflate.

zlib.constants

أضيف مع الإصدار: v 7.0.0.

يوفر كائن لعد الثوابت المرتبطة بـ Zlib.

zlib.createDeflate([options])‎

أُضيف مع الإصدار: v0.5.8.

ينشئ كائن Deflate جديد ويُعيده.

zlib.createDeflateRaw([options])‎

أُضيف مع الإصدار: v0.5.8.

يُنشئ كائن DeflateRaw جديد ويُعيده.

غيرت ترقية zlib من الإصدار 1.2.8 إلى 1.2.11 من سلوكه عند ضبط windowBits بالقيمة 8 لتدفقات الانكماش الخام. سيضبط zlib قيمة windowBits إلى 9 تلقائيا إذا ضُبِط في البداية إلي 8. ستُجري الإصدارات الأحدث من zlib استثناءً، بحيث تستعيد Node.js السلوك الأصلي لترقية القيمة 8 إلى 9، إذ يُنتِج تمرير windowBits = 9 إلى zlib فعليًا دفقًا مضغوطًا يستخدم إطار 8-بت فقط بشكل فعَّال.

zlib.createGunzip([options])‎

أُضيف مع الإصدار: v0.5.8.

ينشئ كائن Gunzip جديد ويُعيده.

zlib.createGzip([options])‎

أُضيف مع الإصدار: v0.5.8.

ينشئ كائن Gzip جديد ويُعيده.

zlib.createInflate([options])‎

أُضيف مع الإصدار: v0.5.8.

ينشئ كائن Inflate جديد ويُعيده.

zlib.createInflateRaw([options])‎

أُضيف مع الإصدار: v0.5.8.

ينشئ كائن InflateRaw جديد ويُعيده.

zlib.createUnzip([options])‎

أُضيف مع الإصدار: v0.5.8.

ينشئ كائن Unzip جديد ويُعيده.

توابع الملاءمة

تتخذ جميع هذه التوابع أيًا من Buffer أو TypedArray أو DataView أو ArrayBuffer أو ‎<string>‎ كوسيط أول، ويكون الوسيط الثاني اختياريًا لتوفير الخيارات لأصناف zlib، وستُسدعي دالة رد الاتصال المُعطاة مع callback(error, result)‎.

ولكل تابع نظير ‎*Sync، والذي يقبل نفس الوسائط، ولكن من دون دالة رد الاتصال.

zlib.deflate(buffer[, options], callback)‎

zlib.deflateSync(buffer[, options])‎

فك ضغط كتلة من البيانات باستخدام Deflate.

zlib.deflateRaw(buffer[, options], callback)‎

zlib.deflateRawSync(buffer[, options])‎

ضغط كتلة من البيانات باستخدام DeflateRaw.

zlib.gunzip(buffer[, options], callback)‎

zlib.gunzipSync(buffer[, options])‎

فك ضغط كتلة من البيانات باستخدام Gunzip.

zlib.gzip(buffer[, options], callback)‎

zlib.gzipSync(buffer[, options])‎

ضغط كتلة من البيانات باستخدام Gzip.

zlib.inflate(buffer[, options], callback)‎‎

zlib.inflateSync(buffer[, options])‎‎

فك ضغط كتلة من البيانات باستخدام Inflate.

zlib.inflateRaw(buffer[, options], callback)‎‎

zlib.inflateRawSync(buffer[, options])‎‎

فك ضغط كتلة من البيانات باستخدام InflateRaw.

zlib.unzip(buffer[, options], callback)‎

zlib.unzipSync(buffer[, options])‎

فك ضغط كتلة من البيانات باستخدام Unzip.

مصادر