Node.js streamek: FileStream, pipe-ok és események
⚡ Okos összefoglaló
A Node.js streamek kis darabokban olvassák és írják az adatokat ahelyett, hogy teljes fájlokat töltenének be a memóriába, és ez az oldal bemutatja a fájlfolyamok létrehozását, a pipe chainelést, a backpressure kezelését és az eseménymodellt, amely hatékonyan tartja a nagyméretű adatátvitelt.

Streamek típusai a Node.js-ben
Minden, a Node.js által elérhető stream négy alaptípus egyikébe tartozik, és egy adott API által visszaadott típus ismerete megmagyarázza, hogyan viselkedik az adott stream, mielőtt bármilyen kódot megírnának. A Node.js-sel együtt szállított stream modul definiálja ezeket a kategóriákat, és a cikkben használt fájl-, hálózati- és tömörítési API-k mind ezekre épülnek.
| Stream típusa | Adatirány | Példa API | Általános használati eset |
|---|---|---|---|
| Readable | Csak forrás (kimenő adatok) | fs.createReadStream() | Fájl olvasása, HTTP kérés törzsének fogadása |
| Írható | Csak célállomás (bejövő adatfolyam) | fs.createWriteStream() | Fájl írása, HTTP válasz küldése |
| Duplex | Mindkét irányban, függetlenül | net.Socket (TCP socket) | Kétirányú hálózati kommunikáció |
| Átalakítás | Mindkét irányban az adatok módosulnak átvitel közben | zlib.createGzip() | Adatok tömörítése vagy kódolása folyamat közben |
Az olvasható és az írható adatfolyam a cikkben használt két építőelem; mindkettő működtet egy HTTP webszerver A Node.js-ben. Egy duplex adatfolyam egyetlen objektumban egyesíti mindkét szerepet, míg egy transzform adatfolyam egy olyan duplex adatfolyam, amelynek kimenete módosítja a bemenetét, például a folyam közepén alkalmazott gzip tömörítést.
Fájlfolyam a Node.js-ben
A négy adatfolyam-kategória meghatározása után a cikk további része egy fájlátvitelt épít fel az olvasható és írható adatfolyam-API-k használatával.
A Node széles körben használja a streameket adatátviteli mechanizmusként.
Ha például a console.log függvény segítségével bármit kiír a konzolra, akkor valójában egy adatfolyamot használ az adatok konzolra való elküldésére.
A Node.js képes arra is, hogy adatfolyamokat tudjon fájlokból streamelni, így azok megfelelően olvashatók és írhatók. Most egy példát tekintünk meg arra, hogyan használhatunk adatfolyamokat fájlokból való olvasásra és írásra. Ehhez a példához az alábbi lépéseket kell követnünk
Step 1) Hozzon létre egy data.txt nevű fájlt, amely az alábbi adatokat tartalmazza. Tegyük fel, hogy ez a fájl a helyi gépünk D meghajtóján van tárolva.
Oktatóanyag a Node.js-ről
Bevezetés
Események
Adatkapcsolat
Jázmin használata
Step 2) Írja be a megfelelő kódot, amely adatfolyamokat használ az adatok olvasásához a fájlból.
var fs = require("fs"); var stream; stream = fs.createReadStream("D://data.txt"); stream.on("data", function(data) { var chunk = data.toString(); console.log(chunk); });
Code Magyarázat:-
- Először is be kell építenünk az „fs” modulokat, amelyek tartalmazzák az adatfolyamok létrehozásához szükséges összes funkciót.
- Ezután létrehozunk egy olvasható adatfolyamot a createReadStream metódussal. Bemenetként megadjuk a data.txt fájlunk helyét.
- A steam.on függvény egy eseménykezelő, és ebben az első paramétert 'data'-ként adjuk meg. Ez azt jelenti, hogy valahányszor adat érkezik az adatfolyamba a fájlból, hajtson végre egy visszahívási funkciót. Esetünkben egy visszahívási funkciót határozunk meg, amely 2 alapvető lépést hajt végre. Az első az, hogy a fájlból kiolvasott adatokat karakterláncként konvertálja. A második az lenne, hogy a konvertált karakterláncot kimenetként küldje el a konzolnak.
- Az adatfolyamból kiolvasott minden adatdarabot sztringgé alakítunk.
- Végül minden egyes átalakított karakterlánc kimenetét elküldjük a konzolnak.
output:
- Ha a kód megfelelően fut, akkor a fenti kimenetet fogja látni a konzolon. Ez a kimenet ugyanaz lesz, mint a data.txt fájlban.
Fájlba írás
Ugyanúgy, mint egy olvasási adatfolyamot, létrehozhatunk írási adatfolyamot is az adatok fájlba írásához. Először hozzunk létre egy üres, tartalom nélküli fájlt data.txt néven. Tegyük fel, hogy ez a fájl a számítógépünk D meghajtójában van.
Az alábbi kód megmutatja, hogyan írhatunk adatokat a fájlba.
var fs = require("fs"); var stream; stream = fs.createWriteStream("D://data.txt"); stream.write("Tutorial on Node.js") stream.write("Introduction") stream.write("Events") stream.write("Generators") stream.write("Data Connectivity") stream.write("Using Jasmine")
Code Magyarázat:-
- Írható adatfolyamot készítünk a createWriteStream módszerrel. Bemenetként megadjuk a data.txt fájlunk helyét.
- Ezt követően a stream.write metódussal írtuk be a különböző szövegsorokat a szövegfájlunkba. A stream gondoskodik arról, hogy ezeket az adatokat a data.txt fájlba írja.
Ha megnyitja a data.txt fájlt, a következő adatokat fogja látni a fájlban
Oktatóanyag a Node.js-ről
Bevezetés
Események
Generators
Adatkapcsolat
<p></p> Jázmin
Csövek a Node.js-ben
A streamek külön-külön olvasása és írása hasznos, de a Node.js lehetővé teszi egy olvasható stream közvetlen csatlakozását egy írható streamhez, így manuális pufferelési kód nélkül mozgathatja az adatokat.
A csomópont-alkalmazásokon belül a folyamokat a pipe() metódussal lehet összevezetni, amely két argumentumot vesz igénybe:
- Egy kötelező írható adatfolyam, amely az adatok és az adatok célhelyeként szolgál
- Opcionális objektum, amely opciók átadására szolgál.
Tipikus példa a csövek használatára, ha adatokat szeretne átvinni egyik fájlból a másikba.
Lássunk tehát egy példát arra, hogyan vihetünk át adatokat egyik fájlból a másikba csövek segítségével.
Step 1) Hozzon létre egy datainput.txt nevű fájlt, amely az alábbi adatokat tartalmazza. Tegyük fel, hogy ez a fájl a helyi gépünk D meghajtóján van tárolva.
Oktatóanyag a Node.js-ről
Bevezetés
Események
Generators
Adatkapcsolat
Jázmin használata
Step 2) Hozzon létre egy üres üres fájlt dataOutput.txt néven, és helyezze el a helyi gép D meghajtójára.
Step 3) Írja be az alábbi kódot, hogy végrehajtsa az adatok átvitelét a datainput.txt fájlból a dataOutput.txt fájlba.
var fs = require("fs"); var readStream = fs.createReadStream("D://datainput.txt"); var writeStream = fs.createWriteStream("D://dataOutput.txt"); readStream.pipe(writeStream);
Code Magyarázat:-
- Először létrehozunk egy „readstreamet” a datainput.txt fájlunkhoz, amely tartalmazza az összes adatunkat, amelyet át kell vinni az új fájlba.
- Ezután létre kell hoznunk egy „írási adatfolyamot” a dataOutput.txt fájlunkhoz, amely az üres fájlunk, és a datainput.txt fájlból történő adatátvitel célállomása.
- Ezután a pipe paranccsal továbbítjuk az adatokat az olvasási adatfolyamból az írási adatfolyamba. A pipe parancs minden adatot átvesz, amely az olvasási adatfolyamba érkezik, és továbbítja az írásfolyamba.
Ha most megnyitja a dataOutput.txt fájlt, látni fogja az összes adatot, amely a datainput.txt fájlban volt.
Stream események és ellennyomás a Node.js-ben
A pipe() hívása, ahogy fentebb látható, két olyan mechanikát rejt, amelyek nagy léptékben számítanak: az egyes streamek által kibocsátott eseményeket, és az ellennyomás-rendszert, amely megakadályozza, hogy egy gyors forrás túlterheljen egy lassú célállomást.
- adatok: egy olvasható adatfolyam bocsát ki minden alkalommal, amikor egy új adatcsomag válik elérhetővé.
- vége: akkor kerül kibocsátásra, amikor egy olvasható adatfolyam leadta az utolsó darabját.
- Befejez: egy írható adatfolyam bocsátja ki, miután az összes sorban álló adat kiürült.
- hiba: bármelyik streamtípus által kibocsátva hiba esetén; mindig kezelje, különben a folyamat összeomlik.
Az alábbi példa mind a négy eseményre figyel, miközben manuálisan kezeli az ellennyomást, ugyanazt a viselkedést biztosítva automatikusan a pipe() függvénynek.
var fs = require("fs"); var readStream = fs.createReadStream("D://data.txt"); var writeStream = fs.createWriteStream("D://dataOutput.txt"); readStream.on("data", function(chunk) { var ok = writeStream.write(chunk); if (!ok) { readStream.pause(); } }); writeStream.on("drain", function() { readStream.resume(); }); readStream.on("end", function() { writeStream.end(); }); writeStream.on("finish", function() { console.log("Write completed."); }); readStream.on("error", function(err) { console.log(err); });
Ellennyomás akkor fordul elő, amikor egy olvasható adatfolyam gyorsabban állítja elő az adatokat, mint ahogy egy írható adatfolyam fel tudja használni azokat. A write() metódus hamis értéket ad vissza, ha a puffer megtelik, így a fenti kód szünetelteti a forrást, amíg a cél egy drain eseményt nem generál, jelezve, hogy biztonságos a folytatás. A pipe() metódus ezt a ciklust automatikusan végrehajtja.
⚠ Tipp: Éles környezetben a stream modul pipeline() függvényét részesítsd előnyben a manuális pipe() lánccal szemben, mivel az minden streamből továbbítja a hibákat, és automatikusan lezárja a fájlkezelőket.
Események a Node.js-ben
A streamek a Node.js tágabb eseményvezérelt felépítésének egyik példája. A cikk további része az események általános működését vizsgálja, ugyanazt az EventEmitter osztályt használva, amelyre a streamek belsőleg támaszkodnak.
Az események a Node.js egyik kulcsfogalma, és néha a Node.js-t eseményvezérelt keretrendszernek nevezik.
Alapvetően egy esemény valami megtörténik. Például, ha létrejön egy kapcsolat egy adatbázissal, akkor az adatbázis-csatlakozási esemény aktiválódik. Az eseményvezérelt programozás olyan funkciókat hoz létre, amelyek bizonyos események indításakor aktiválódnak.
Nézzünk egy alapvető példát egy esemény Node.js-ben történő meghatározására.
Létrehozunk egy eseményt 'data_received' néven. Amikor ez az esemény aktiválódik, az „adat érkezett” szöveg kerül elküldésre a konzolra.
var events = require('events'); var eventEmitter = new events.EventEmitter(); eventEmitter.on('data_received', function() { console.log('data received succesfully.'); }); eventEmitter.emit('data_received');
Code Magyarázat:-
- Használja a követelmény függvényt az „események” modul felvételéhez. Ezzel a modullal eseményeket hozhat létre a Node.js-ben.
- Hozzon létre egy új eseménykibocsátót. Ez arra szolgál, hogy az eseményt, ami esetünkben „data_received” egy visszahívási függvényhez kötjük, amelyet a 3. lépésben definiálunk.
- Definiálunk egy eseményvezérelt függvényt, amely azt mondja, hogy ha a „data_received” esemény aktiválódik, akkor a „data_received” szöveget kell kiadnunk a konzolba.
- Végül, van egy manuális triggerünk az eseményünkhöz az eventEmiter.emit függvény használatával. Ez elindítja a data_received eseményt.
A program futtatásakor az „adat fogadott” szöveg kerül elküldésre a konzolra az alábbiak szerint.
Események kibocsátása
Az események kibocsátásán és figyelésén túl a Node.js további metódusokat is kínál a figyelők regisztrációjának és ellenőrzésének szabályozására.
Az események definiálásakor különböző módszerek állnak rendelkezésre az eseményekhez, amelyek meghívhatók. Ez a téma mindegyikük részletes vizsgálatára összpontosít.
- Egyszeri eseménykezelők
Előfordulhat, hogy csak az első alkalommal szeretne reagálni egy eseményre. Ilyen helyzetekben használhatja a Once() metódust.
Nézzük meg, hogyan használhatjuk az egyszeri módszert az eseménykezelők számára.
Code Magyarázat:-
- Itt az "once" metódust használjuk, hogy azt mondjuk, hogy a "data_received" eseménynél a visszahívási függvényt csak egyszer szabad végrehajtani.
- Itt manuálisan indítjuk el a 'data_received' eseményt.
- Ha a 'data_received' esemény ismét aktiválódik, ezúttal semmi sem fog történni. Ez az első lépés miatt van így, amikor azt mondtuk, hogy az esemény csak egyszer indítható el.
Ha a kódot megfelelően hajtják végre, a napló kimenete a „data_received sikeresen” lesz. Ez az üzenet csak egyszer jelenik meg a konzolon.
- Eseményfigyelők ellenőrzése
Életének bármely szakaszában egy eseménykibocsátóhoz nulla vagy több hallgató csatlakozhat. Az egyes eseménytípusok figyelői többféleképpen is ellenőrizhetők.
Ha csak a csatolt figyelők számát szeretné meghatározni, akkor ne keresse tovább az EventEmitter.listenerCount() metódust.
(Jegyzet: A hallgatók azért fontosak, mert a fő programnak tudnia kell, ha a hallgatókat menet közben adják hozzá egy eseményhez, különben a program hibásan működik, mert további hallgatókat hívnak meg.)
Code Magyarázat:-
- Definiálunk egy eventEmitter típust, amely az eseményfüggő metódusok használatához szükséges.
- Ezután definiálunk egy emitter nevű objektumot, amelyet eseménykezelőink meghatározásához használunk.
- Két eseménykezelőt hozunk létre, amelyek gyakorlatilag semmit sem csinálnak. Példánkban ez egyszerű, csak azért, hogy megmutassa, hogyan működik a listenerCount metódus.
- Most, amikor meghívja a listenerCount metódust a data_received eseményünkön, elküldi az eseményhez kapcsolódó eseményfigyelők számát a konzolnaplóban.
Ha a kód megfelelően fut, akkor a 2-es érték jelenik meg a konzolnaplóban.
- Az új Listener esemény
Minden alkalommal, amikor egy új eseménykezelőt regisztrálnak, az eseménykibocsátó egy newListener eseményt bocsát ki. Ez az esemény az új eseménykezelők észlelésére szolgál. Általában akkor használja a newListener eseményt, amikor erőforrásokat kell lefoglalnia vagy valamilyen műveletet kell végrehajtania minden új eseménykezelőhöz.
var events = require('events'); var eventEmitter = events.EventEmitter; var emitter = new eventEmitter(); emitter.on("newListener", function(eventName, listener) { console.log("Added listener for " + eventName + " events"); }); emitter.on('data_received', function() {}); emitter.on('data_received', function() {});
Code Magyarázat:-
- Új eseménykezelőt hozunk létre a „newListener” eseményhez. Így amikor új eseménykezelőt regisztrálnak, a „Added listener for” + az esemény neve szöveg jelenik meg a konzolon.
- Itt írjuk a konzolba a „Hozzáadott figyelő” szöveget + az esemény nevét minden regisztrált eseményhez.
- 2 eseménykezelőt határozunk meg a 'data_received' eseményünkhöz.
Ha a fenti kód megfelelően fut, az alábbi szöveg jelenik meg a konzolon. Ez csak azt mutatja, hogy a „newListener” eseménykezelő kétszer indult el.
Figyelő hozzáadva a data_received eseményekhez
Figyelő hozzáadva a data_received eseményekhez









