30 روز با Node - روز پانزدهم: جریان داده ها یا استریم (Stream) در نود جی اس

29 مرداد 1397
stream-nodejs

 استریم در نود جی اس

  • یک استریم (Stream) برای کار با جریان داده ها در نود جی اس به کار می رود
  • استریم ها می توانند خواندنی یا نوشتنی یا هردو باشند.
  • همه ی استریم ها نمونه هایی از کلاس eventEmitter هستند.
  • برای کار با استریم ها در نود جی اس، از ماژول stream استفاده می کنیم. همانند باقی ماژولها، به صورت زیر عمل کنید:
var stream = require('stream');			

انواع استریم ها

چهارنوع استریم در نود جی اس وجود دارد:

  1. استریم خواندنی (Readable): استریمی که برای انجام عملیات خواندن استفاده می شود، استریم خواندنی است.
  2. استریم نوشتنی (Writable): استریمی که برای انجام عملیات نوشتن استفاده می شود، استریم نوشتنی است.
  3. استریم دوسویه (Duplex): استریمی که هم خواندنی و هم نوشتنی باشد، یک استریم دوسمتی است.
  4. استریم تبدیل (Transform): یک نوع استریم دوسمتی است که می تواند داده ها را همانطور که خوانده یا نوشته می شوند، ویرایش کند یا تبدیل نماید. همچنین، در استریم از نوع تبدیل، خروجی تاحدودی وابسته به ورودی است.

استریم خواندنی

این نوع استریم، عملیات خواندن انجام می دهد. همه جنبه های استریم خواندنی به شرح زیر است:

  • وضعیت: دو وضعیت برای استریم های خواندنی موجود است:
    1. متوقف شده:
      • اگر استریم خواندنی در وضعیت متوقف شده باشد، باید به کمک فراخوانی صریح متد stream.read() مقدار قابل توجهی از داده ها را بخوانیم.
      • بطور پیش فرض، همه ی استریم های خواندنی در وضعیت متوقف شده قرار دارند.
      • برای پرش به وضعیت  «متوقف شده» در استریم خواندنی، از متد stream.pause() استفاده کنید.
      • همچنین در استریم های خواندنی، وقتی مقصدهای پایپ (pipe) در دسترس باشند، می توان از متد stream.unpipe() برای پرش به وضعیت متوقف شده استفاده کرد.
    2. درجریان:
      • چنانچه استریم خواندنی در وضعیت «درجریان» باشد، بدین معناست که داده ها با موفقیت ارسال شده اند.
      • برای پرش به وضعیت «درجریان»، متد stream.resume() را به کار ببرید (برای استریمی که قبلا stream.pause() شده)
      • همچنین می توان برای پرش به وضعیت «درجریان»، از متد stream.pipe() استفاده کرد. (برای استریمی که قبلا stream.unpipe() شده)
      • اگر استریم خواندنی در وضعیت «درجریان» باشد و هیچ مصرف کننده ای برای داده های وجود نداشته باشد، باعث از دست رفتن داده ها خواهد شد.
  • مثال ها: چند مثال از متدها یا ماژولهایی که مستقیما از استریم خواندنی استفاده می کنند یا به فرم دوسویه/تبدیل هستند، به شرح زیر آمده اند:
    • تقاضای HTTP از سمت سرور (Server Request)
    • پاسخ HTTP از سمت کاربر (Client Response)
    • ماژول fs برای خواندن استریم ها
    • ماژول zlib
    • سوکت TCP
    • process.stdin
  • رخدادها:
    • readable: این رخداد زمانی رخ می دهد که داده ای برای خواندن در استریم وجود داشته باشد.
    • data: وقتی رخ می دهد که استریم در حال تخلیه تنه داده ها (data chunk) به مصرف کننده است.
    • error: وقتی رخ می دهد که استریم بنا به دلایل داخلی قادر تولید داده نیست یا اینکه تلاش در جهت ارسال تنه ی بی ارزشی از داده است.
    • close: وقتی رخ می دهد که استریم بسته می شود. مشخص می کند که دیگر نه رخدادی به قوع می پیوندد و نه محاسباتی انجام می گیرد.
    • end: زمانی رخ می دهد که همه داده ها خوانده شوند. بدین معنی است که دیگر داده ایی برای مصرف کننده وجود ندارد.
  • متدها:
    1. readable.pause() : تغییر وضعیت از «درجریان» به «متوقف شده». با این کار داده ها در بافر ساکن خواهند شد.
    2. readable.resume() : تغییر وضعیت از «متوقف شده» به «درجریان». استریم ارسال رخدادها را نیز ادامه خواهد داد.
    3. readable.isPaused() : بررسی می کند آیا وضعیت فعلی استریم، «متوقف شده» است با خیر. مقدار true و false برمی گرداند.
    4. readable.pipe() : این متد زمانی به کار می رود که بخواهیم یک استریم نوشتنی را به یک استریم خواندنی متصل کنیم تا وضعیت از «متوقف شده» به «درجریان» تغییر کند و ارسال داده ها به سمت استریم نوشتنی شروع شود.
    5. readable.unpipe() : متدی برای قطع اتصال یک استریم نوشتنی که به استریم خواندنی متصل شده است.
    6. readable.read() : برای بیرون کشیدن داده ها از بافر داخلی از این متد استفاده کنید، دیتایی که برگردانده می شود، به فرم بافر خواهد بود مگر اینکه فرمت دیگری توسط readable.setEncoding() مشخص شده باشد. اگر داده ای برای بیرون کشیدن از بافر موجود نباشد، مقدار null برگردانده می شود.
    7. readable.setEncoding() : متدی که برای انکد کردن استریم خواندنی به کار می رود. درحالت پیش فرض، داده ها به فرم بافر بیرون کشیده می شوند.
    8. readable.unshift() : این متد برای بازگرداندن داده ها به بافر داخلی به کار می رود.
    9. readable.wrap() : وقتی که منابع داده ها از استریم های قدیمی استفاده می کنند و بخواهید داده ها را از استریم های خواندنی بخوانید، از این متد استفاده کنید
    10. readable.destroy() : از این متد زمانی استفاده می شود که بخواهیم پایان یک استریم خواندنی را مشخص کنیم و استریم هم درصورتی که منابعی را دراختیار گرفته باشد، آزاد کند.

استریم های نوشتنی

استریم هایی که به منظور انجام عمل نوشتن مورد استفاده قرار می گیرند، از نوع استریم خواندنی هستند. تمام جنبه های استریم خواندنی در زیر توضیح داده شده است:

  • مثال ها: نمونه هایی از متدها یا ماژول هایی که از استریم نوشتنی استفاده می کنند، در زیر آمده است:
    • تقاضاهای HTTP سمت کاربر (Client Requet)
    • پاسخ های HTTP سمت سرور (Server Response)
    • ماژول fs برای نوشتن استریم ها
    • ماژول zlib
    • ماژول crypto
    • سوکت TCP
    • process.stdout
    • process.stderr
  •   رخدادها:
    •  drain: وقتی که یک فراخوانی به متد system.write(chunk) مقدار false بر می گرداند این رخداد صادر می شود و به کمک آن می توان مشخص کرد چه زمانی وقت ادامه کار نوشتن است.
    • pipe: این رخداد وقتی صادر می شود که فراخوانی متد stream.pipe() روی یک استریم خواندنی انجام گیرد و مشخص می کند که استریم نوشتنی به مجموعه ی استریم های خواندنی افزوده شده.
    • unpipe: این رخداد وقتی روی می دهد که متد stream.unpipe() روی یک استریم خواندنی فراخوانی می شود و مشخص کننده این است که استریم نوشتنی از مجموعه استریمهای خواندنی برداشته شده است.
    • error: وقتی در حال نوشتن یا عمل پایپ داده ها خطایی اتفاق بیفتد، این رخداد روی می دهد.
    • close: این رخداد زمان بسته شدن استریم رخ می دهد. مشخص می کند که دیگر هیچ رخدادی صادر نمی شود و دیگر هیچ محاسباتی اتفاق نخواهد افتاد.
    • finish: وقتی تمام داده ها با موفقیت خالی شدند، این رخداد صادر می شود.
  • متدها:
    1. writable.cork() : این متد باعث می شود که تمام داده های نوشته شده اجبارا در حافظه بافر شوند تا بعدا بوسیله یکی از سناریوهای زیر خالی شوند:
      • فراخوانی متد stream.uncork().
      • فراخوانی متد stream.end().
    2. writable.uncork(): از این متد برای خالی کردن داده هایی که توسط writable.cork() بافر شده اند، استفاده کنید.
    3. writable.write() : متدی برای نوشتن داده هایی در استریم و فراخوانی تابع کال بک زمانی که داده ها با موفقیت رسیدگی شدند.
    4. writable.setDefaultEncoding() : این متد برای تعیین انکودینگ پیش فرض برای استریم های نوشتنی استفاده می شود.
    5. writable.end() : متدی که مشخص می کند داده ای برای نوشتن در استریم نوشتنی وجود ندارد.
    6. writable.destroy() : این متد مشخص می کند که استریم نوشتنی به انتها رسیده است.

استریم دوسویه (Duplex)

این استریم بطور همزمان هر دو نوع استریم خواندنی و نوشتنتی را پیاده سازی می کند. پرکاربردترین مثال این استریم، net.socket است که خود کلاسی از ماژول net است. برای درک بهتر استریم دوسویه توضیحاتی ارائه می دهیم.

همانطور که در روز 14 توضیح دادیم، سوکتها می توانستند برای انجام عملیات همزمان در نود جی اس به کار روند. فرض کنید یک سوکت ساخته ایم تا عملیات ارسال و دریافت داده ها را همزمان انجام دهد. این کار با استریم دوسویه هم حاصل می شود. ما دو کانال مستقل در شبکه خواهیم داشت که یکی برای انتقال و دیگری برای دریافت داده ها استفاده می شود.

  • مثال های از استریم دوسویه: نمونه هایی از متدها یا ماژولهای دوسویه در زیر آمده است:
    • سوکتها (TCP) : از استریم دوسویه برای پیاده سازی سوکت استفاده می کند.
    • Zlib : از استریم های دوسویه برای فشرده سازی gzip و برعکس استفاده می کند.
    • crypto : برای رمزگذاری (Encryption) و رمزگشایی (Decrtyption) و ایجاد خلاصه پیام (message digest) در رمزنگاری (Cryptography) ار استریم دوسویه استفاده می کند.

استریم تبدیل (Transfrom)

استریم تبدیل، نوعی استریم دوسویه است که داده ها را در حین خوانده شدن یا نوشته شدن، تبدیل می کند یا تغییر می دهد. همچنین در جایی که خروجی به ورودی مرتبط است این نوع استریم به کار می رود. این استریم ها داده های ورودی را خوانده و به کمک توابعی آنها را همانند شکل زیر به خروجی تبدیل می کنند.

معرفی استریم تبدیل در نود جی اس

همچنین می توانیم استریم ها را بصورت زنجیره ای از پایپ ها به یکدیگر متصل کنیم تا قادر به اجرای پردازش های پیچیده باشند:

نمایش شماتیک استریم تبدیل (Transform)

  • مثالها: متدها و ماژولهایی که از استریمهای تبدیل بهره می برند در زیر آمده اند:
    • zlib: این ماژول از استریم تبدیل برای فشرده سازی و عدم فشرده سازی استفاده می کند، همانند متد zlib.createDeflate .
    • crypto: این ماژول نیز از استریم تبدیل برای انجام عملیات رمزگذاری و رمزگشایی و ایجاد خلاصه پیام در رمزنگاری استفاده می کند.
  • متدها:
    1. transform.destroy() : این متد استریم را نابود کرده و رخداد error را صادر می کند. همچنین باعث می شود که تمام منابع داخلی مورد مصرف، آزاد شود.

نمونه کد مثال

قطعه کد زیر نشان می دهد که چگونه می توان از استریم ها در نود جی اس استفاده نمود:

// require fs module for file system
var fs = require('fs');
// write data to a file using writeable stream
var wdata = "I am working with streams for the first time";

var myWriteStream = fs.createWriteStream('aboutMe.txt');

// write data 

myWriteStream.write(wdata);

// done writing
myWriteStream.end();

// write handler for error event 
myWriteStream.on('error', function(err){
   console.log(err);
});

myWriteStream.on('finish', function() {
    console.log("data written successfully using streams.");
	console.log("Now trying to read the same file using read streams ");
	var myReadStream = fs.createReadStream('aboutMe.txt');
	// add handlers for our read stream
	var rContents = '' // to hold the read contents;
	myReadStream.on('data', function(chunk) {
		rContents += chunk;
	});
	myReadStream.on('error', function(err){
		console.log(err);
	});
	myReadStream.on('end',function(){
		console.log('read: ' + rContents);
	});
	console.log('performed write and read using streams');

});		

و مثل همیشه، برای اجرا، دستور زیر را در ترمینال یا خط فرمان وارد کنید:

> node filename_streams.js		

خلاصه

در این بخش از دوره آموزشی 30 روز با نود جی اس، مبانی استریم ها را یادگرفتیم، استریم چیست، انواع استریم ها (خواندنی، نوشتنی، دوسویه و تبدیل) و در نهایت یک کد به عنوان مثال در مورد نحوه استفاده از استریم ها نوشتیم.

نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.