Node.js
धाराओं का उपयोग करना
खोज…
पैरामीटर
पैरामीटर | परिभाषा |
---|---|
पठनीय स्ट्रीम | उस स्ट्रीम का प्रकार जहां से डेटा पढ़ा जा सकता है |
लिखने योग्य स्ट्रीम | उस स्ट्रीम का प्रकार जहां डेटा को लिखा जा सकता है |
डुप्लेक्स स्ट्रीम | स्ट्रीम का प्रकार जो पठनीय और लिखने योग्य दोनों है |
ट्रांसफॉर्म स्ट्रीम | डुप्लेक्स स्ट्रीम का प्रकार जो डेटा को रूपांतरित कर सकता है क्योंकि यह पढ़ा जा रहा है और फिर लिखा जा रहा है |
धाराओं के साथ TextFile से डेटा पढ़ें
नोड में I / O अतुल्यकालिक है, इसलिए डिस्क और नेटवर्क के साथ कार्य करने के लिए कॉलबैक को पास करना शामिल है। आपको कोड लिखने के लिए लुभाया जा सकता है जो डिस्क से एक फ़ाइल को इस तरह से कार्य करता है:
var http = require('http');
var fs = require('fs');
var server = http.createServer(function (req, res) {
fs.readFile(__dirname + '/data.txt', function (err, data) {
res.end(data);
});
});
server.listen(8000);
यह कोड काम करता है, लेकिन यह ग्राहकों के लिए वापस परिणाम लिखने से पहले हर अनुरोध के लिए मेमोरी में पूरी data.txt फ़ाइल को भारी और बफ़र करता है। यदि data.txt बहुत बड़ा है, तो आपका प्रोग्राम बहुत सी मेमोरी खाना शुरू कर सकता है क्योंकि यह बहुत सारे उपयोगकर्ताओं को समवर्ती रूप से कार्य करता है, विशेष रूप से धीमे कनेक्शन वाले उपयोगकर्ताओं के लिए।
उपयोगकर्ता का अनुभव भी खराब है क्योंकि उपयोगकर्ताओं को किसी भी सामग्री को प्राप्त करना शुरू करने से पहले आपके सर्वर पर मेमोरी में बफ़र होने के लिए पूरी फ़ाइल की प्रतीक्षा करनी होगी।
सौभाग्य से दोनों (रीक, रेस) तर्क धाराएँ हैं, जिसका अर्थ है कि हम इसे fs.createReadStream () के बजाय fs.readFile () का उपयोग करके बहुत बेहतर तरीके से लिख सकते हैं:
var http = require('http');
var fs = require('fs');
var server = http.createServer(function (req, res) {
var stream = fs.createReadStream(__dirname + '/data.txt');
stream.pipe(res);
});
server.listen(8000);
यहाँ .pipe () fs.createReadStream () से 'डेटा' और 'एंड' ईवेंट को सुनने का ध्यान रखता है। यह कोड न केवल क्लीनर है, बल्कि अब डेटाटेक्स्ट फ़ाइल को क्लाइंट को एक बार में एक बार तुरंत लिखा जाएगा, क्योंकि वे डिस्क से प्राप्त होते हैं।
पाइपिंग स्ट्रीम
पठनीय धाराएँ "" पाइप की जा सकती हैं, "या जुड़ी हुईं, जो विचारणीय धाराओं में होती हैं। यह बहुत अधिक प्रयास के बिना स्रोत धारा से गंतव्य स्थान तक डेटा प्रवाह बनाता है।
var fs = require('fs')
var readable = fs.createReadStream('file1.txt')
var writable = fs.createWriteStream('file2.txt')
readable.pipe(writable) // returns writable
जब लिखने योग्य धाराएँ पठनीय धाराएँ होती हैं, यानी जब वे द्वैध धाराएँ होती हैं, तो आप इसे अन्य लेखन योग्य धाराओं तक जारी रख सकते हैं।
var zlib = require('zlib')
fs.createReadStream('style.css')
.pipe(zlib.createGzip()) // The returned object, zlib.Gzip, is a duplex stream.
.pipe(fs.createWriteStream('style.css.gz')
पठनीय धाराएँ भी कई धाराओं में पाई जा सकती हैं।
var readable = fs.createReadStream('source.css')
readable.pipe(zlib.createGzip()).pipe(fs.createWriteStream('output.css.gz'))
readable.pipe(fs.createWriteStream('output.css')
ध्यान दें कि किसी भी डेटा 'फ़्लो' से पहले आपको आउटपुट स्ट्रीम पर समान रूप से (उसी समय) पाइप करना होगा। ऐसा करने में विफलता के कारण अपूर्ण डेटा प्रवाहित हो सकता है।
यह भी ध्यान दें कि स्ट्रीम ऑब्जेक्ट error
घटनाओं का उत्सर्जन कर सकते हैं; जिम्मेदारी से आवश्यकतानुसार हर स्ट्रीम पर इन घटनाओं को संभालने के लिए सुनिश्चित हो:
var readable = fs.createReadStream('file3.txt')
var writable = fs.createWriteStream('file4.txt')
readable.pipe(writable)
readable.on('error', console.error)
writable.on('error', console.error)
अपनी खुद की पठनीय / लिखने योग्य स्ट्रीम बनाना
हम स्ट्रीम ऑब्जेक्ट्स को fs आदि जैसे मॉड्यूल द्वारा वापस लौटाते हुए देखेंगे लेकिन क्या होगा यदि हम अपनी स्ट्रीम करने योग्य वस्तु बनाना चाहते हैं।
स्ट्रीम ऑब्जेक्ट बनाने के लिए हमें NodeJs द्वारा प्रदान की जाने वाली स्ट्रीम मॉड्यूल का उपयोग करना होगा
var fs = require("fs");
var stream = require("stream").Writable;
/*
* Implementing the write function in writable stream class.
* This is the function which will be used when other stream is piped into this
* writable stream.
*/
stream.prototype._write = function(chunk, data){
console.log(data);
}
var customStream = new stream();
fs.createReadStream("am1.js").pipe(customStream);
यह हमें अपने स्वयं के कस्टम लिखने योग्य स्ट्रीम देगा। हम _write फ़ंक्शन के भीतर कुछ भी लागू कर सकते हैं। उपरोक्त विधि NodeJs 4.xx संस्करण में काम करती है, लेकिन NodeJs में 6.x ES6 ने कक्षाएं शुरू की हैं, इसलिए वाक्यविन्यास बदल गए हैं। नीचे NodeJs के 6.x संस्करण के लिए कोड है
const Writable = require('stream').Writable;
class MyWritable extends Writable {
constructor(options) {
super(options);
}
_write(chunk, encoding, callback) {
console.log(chunk);
}
}
धाराएँ क्यों?
फाइल की सामग्री को पढ़ने के लिए निम्नलिखित दो उदाहरणों की जाँच करें:
पहला, जो किसी फ़ाइल को पढ़ने के लिए एक एसिंक्स विधि का उपयोग करता है, और एक कॉलबैक फ़ंक्शन प्रदान करता है जिसे फ़ाइल को मेमोरी में पूरी तरह से पढ़ने के बाद कहा जाता है:
fs.readFile(`${__dirname}/utils.js`, (err, data) => {
if (err) {
handleError(err);
} else {
console.log(data.toString());
}
})
और दूसरा, जो फ़ाइल की सामग्री को पढ़ने के लिए streams
का उपयोग करता है, टुकड़ा द्वारा टुकड़ा:
var fileStream = fs.createReadStream(`${__dirname}/file`);
var fileContent = '';
fileStream.on('data', data => {
fileContent += data.toString();
})
fileStream.on('end', () => {
console.log(fileContent);
})
fileStream.on('error', err => {
handleError(err)
})
यह ध्यान देने योग्य है कि दोनों उदाहरण एक ही बात करते हैं । फिर क्या फर्क है?
- पहला छोटा है और अधिक सुरुचिपूर्ण दिखता है
- दूसरा आपको पढ़ने के दौरान फ़ाइल पर कुछ प्रोसेसिंग करने देता है (!)
जब आप जिन फ़ाइलों से निपटते हैं वे छोटी होती हैं, तो streams
का उपयोग करते समय कोई वास्तविक प्रभाव नहीं होता है, लेकिन जब फ़ाइल बड़ी होती है तो क्या होता है? (इतना बड़ा कि इसे मेमोरी में पढ़ने में 10 सेकंड लगते हैं)
बिना streams
आप प्रतीक्षा कर रहे होंगे, जब तक कि 10 सेकंड नहीं गुजरते और फाइल पूरी तरह से पढ़ी नहीं जाती , तब तक कुछ भी नहीं (जब तक कि आपकी प्रक्रिया अन्य सामान नहीं करती), और उसके बाद ही आप फ़ाइल को संसाधित करना शुरू कर सकते हैं।
streams
साथ, आपको फ़ाइल की सामग्री का टुकड़ा टुकड़ा से मिलता है, ठीक जब वे उपलब्ध होते हैं - और इससे आप फ़ाइल को पढ़ते समय संसाधित कर सकते हैं।
ऊपर दिए गए उदाहरण में यह नहीं बताया गया है कि कॉलबैक फैशन में जाने पर काम के लिए streams
का उपयोग कैसे किया जा सकता है, इसलिए यह दूसरे उदाहरण पर ध्यान नहीं देता है:
मैं एक gzip
फ़ाइल डाउनलोड करना चाहूंगा, इसे अनज़िप करूँगा और डिस्क पर इसकी सामग्री को सहेज सकता हूँ। फ़ाइल के url
को देखते हुए यह किया जाना चाहिए:
- फ़ाइल डाउनलोड करें
- फ़ाइल खोलना
- इसे डिस्क पर सहेजें
यहां एक [छोटी फ़ाइल] [1] है, जो मेरे S3
स्टोरेज में संग्रहीत है। निम्न कोड ऊपर कॉलबैक फैशन में करता है।
var startTime = Date.now()
s3.getObject({Bucket: 'some-bucket', Key: 'tweets.gz'}, (err, data) => {
// here, the whole file was downloaded
zlib.gunzip(data.Body, (err, data) => {
// here, the whole file was unzipped
fs.writeFile(`${__dirname}/tweets.json`, data, err => {
if (err) console.error(err)
// here, the whole file was written to disk
var endTime = Date.now()
console.log(`${endTime - startTime} milliseconds`) // 1339 milliseconds
})
})
})
// 1339 milliseconds
यह इस तरह से streams
का उपयोग करता streams
:
s3.getObject({Bucket: 'some-bucket', Key: 'tweets.gz'}).createReadStream()
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream(`${__dirname}/tweets.json`));
// 1204 milliseconds
हां, छोटी फ़ाइलों के साथ काम करते समय यह तेज़ नहीं होता है - परीक्षण की गई फ़ाइल का वजन 80KB
। इसे एक बड़ी फ़ाइल पर परीक्षण करना, 71MB
gzipped ( 382MB
unzipped), दिखाता है कि streams
संस्करण बहुत तेज़ है
- कॉलबैक फैशन का उपयोग करते हुए , इसे
71MB
डाउनलोड करने के लिए 20925 मिलीसेकंड लिया गया, इसे अनज़िप किया और फिर382MB
डिस्क पर लिख382MB
। - इसकी तुलना में,
streams
संस्करण का उपयोग करते समय ऐसा करने के लिए 13434 मिलीसेकंड लिया गया (35% तेजी से, एक बड़ी फ़ाइल के लिए)