Node.js vooged: FileStream, torud ja sündmused

⚡ Nutikas kokkuvõte

Node.js voogedastavad andmeid väikeste tükkidena, selle asemel et laadida terveid faile mällu, ning see leht selgitab failivoo loomist, torude aheldamist, vasturõhu käsitlemist ja sündmuste mudelit, mis hoiab suuremahulise andmeedastuse tõhusana.

  • ???? Voo tüübid: Node.js korraldab iga voo loetavaks, kirjutatavaks, dupleksseks või teisendatavaks ning iga Node.js API tagastab ühe neist neljast tüübist.
  • 📂 Failivoog: fs.createReadStream() ja fs.createWriteStream() loevad ja kirjutavad faile tükkidena ilma kogu faili mällu laadimata.
  • 🔗 Piping: Meetod pipe() ühendab loetava voo otse kirjutatava vooga ja liigutab andmeid nende vahel automaatselt.
  • 🇧🇷 Vasturõhk: write() tagastab väärtuse „väär”, kui puhver on täis, ja drain-sündmus annab märku, millal on kirjutamise jätkamine ohutu.
  • 📡 Otseülekande sündmused: Andmed, lõpp, viga ja lõpp tähistavad voo elutsükli võtmehetki ja juhivad enamikku voogu haldavat koodi.
  • Kohandatud sündmused: Sündmuste moodul ja EventEmitter võimaldavad igal Node.js rakendusel defineerida, emiteerida ja kuulata omaenda nimega sündmusi.
  • 🛠️ Kuulaja kontroll: once(), listenerCount() ja newListener sündmused haldavad, mitu korda käitleja töötab ja kuidas kuulajaid kasutatakse. tracked.

Node.js-i voogude tüübid

Iga Node.js-i pakutav voog kuulub ühte neljast baastüübist ja API tagastatava tüübi teadmine selgitab, kuidas see voog enne koodi kirjutamist käitub. Node.js-iga kaasasolev voomoodul määratleb need kategooriad ning selles artiklis kasutatud faili-, võrgu- ja tihendus-API-d on kõik nende peale ehitatud.

Voo tüüp Andmete suund Näidis-API Tavakasutuse juhtum
Readable Ainult allikas (andmed voolavad välja) fs.createReadStream() Faili lugemine, HTTP-päringu sisu vastuvõtmine
Kirjutatav Ainult sihtkoht (andmete sissevool) fs.createWriteStream() Faili kirjutamine, HTTP-vastuse saatmine
Duplex Mõlemad suunad, sõltumatult net.Socket (TCP-pesa) Kahesuunaline võrguside
Muutma Mõlemas suunas, andmeid muudetakse edastamise ajal zlib.createGzip() Andmete tihendamine või kodeerimine torujuhtme keskel

Loetav voog ja kirjutatav voog on kaks ehitusplokki, mida selles artiklis kasutatakse; mõlemad annavad jõudu ka HTTP veebiserver Node.js-is. Dupleksvoog ühendab mõlemad rollid ühes objektis, samas kui teisendusvoog on dupleksvoog, mille väljund muudab sisendit, näiteks gzip-tihendust rakendatakse voo keskel.

Failivoog rakenduses Node.js

Kui neli vookategooriat on määratletud, loob see artikkel ülejäänud osas failiedastuse loetava ja kirjutatava voo API-de abil.

Node kasutab andmeedastusmehhanismina laialdaselt vooge.

Näiteks kui väljastate midagi konsooli funktsiooni console.log abil, kasutate andmete konsooli saatmiseks tegelikult voogu.

Node.js-l on ka võimalus failidest andmeid voogesitada, et neid saaks õigesti lugeda ja kirjutada. Vaatame nüüd näidet selle kohta, kuidas saame failidest lugemiseks ja kirjutamiseks kasutada vooge. Peame selle näite jaoks järgima alltoodud samme

Step 1) Looge fail nimega data.txt, mis sisaldab allolevaid andmeid. Oletame, et see fail on salvestatud meie kohaliku masina D-draivile.

Node.js-i õpetus

Sissejuhatus

Sündmused

Generators

Andmeside

Jasmiini kasutamine

Step 2) Kirjutage asjakohane kood, mis kasutab failist andmete lugemiseks vooge.

Failivoog rakenduses Node.js

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 Selgitus:-

  1. Kõigepealt peame kaasama fs-moodulid, mis sisaldavad kõiki voogude loomiseks vajalikke funktsioone.
  2. Järgmisena loome loetava voo, kasutades meetodit createReadStream. Sisendina anname faili data.txt asukoha.
  3. Funktsioon steam.on on sündmuste töötleja ja selles määrame esimese parameetri kui "andmed". See tähendab, et kui failist voogu tulevad andmed, käivitage tagasihelistamise funktsioon. Meie puhul määratleme tagasihelistamisfunktsiooni, mis viib läbi 2 põhietappi. Esimene on failist loetud andmete teisendamine stringina. Teine oleks teisendatud stringi saatmine väljundina konsooli.
  4. Võtame iga andmevoost loetava andmepaki ja teisendame selle stringiks.
  5. Lõpuks saadame iga stringi teisendatud tüki väljundi konsooli.

Väljund:

Failivoog rakenduses Node.js

  • Kui kood on õigesti käivitatud, näete konsoolis ülaltoodud väljundit. See väljund on sama, mis failis data.txt.

Faili kirjutamine

Samamoodi, kui loome lugemisvoo, saame luua ka kirjutamisvoo andmete faili kirjutamiseks. Loome esmalt tühja faili nimega data.txt. Oletame, et see fail on paigutatud meie arvuti D-draivi.

Allolev kood näitab, kuidas saame faili andmeid kirjutada.

Failivoog rakenduses Node.js

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 Selgitus:-

  1. Loome kirjutatava voo, kasutades meetodit createWriteStream. Sisendina anname faili data.txt asukoha.
  2. Järgmisena kasutasime meetodit stream.write erinevate tekstiridade kirjutamiseks meie tekstifaili. Voog kirjutab nende andmete faili data.txt.

Kui avate faili data.txt, näete nüüd failis järgmisi andmeid

Node.js-i õpetus

Sissejuhatus

Sündmused

Generators

Andmeside

Kasutamine jasmiin

Torud failis Node.js

Voogude iseseisev lugemine ja kirjutamine on kasulik, kuid Node.js võimaldab loetaval vool otse kirjutatava vooguga ühenduse luua, liigutades andmeid ilma käsitsi puhverdamise koodita.

Node rakendustes saab vooge ühendada pipe() meetodi abil, millel on kaks argumenti:

  • Nõutav kirjutatav voog, mis toimib andmete ja
  • Valikuline objekt, mida kasutatakse valikute sisestamiseks.

Tüüpiline näide torude kasutamisest, kui soovite andmeid ühest failist teise üle kanda.

Vaatame siis näidet, kuidas saame torude abil andmeid ühest failist teise üle kanda.

Step 1) Looge fail nimega datainput.txt, mis sisaldab allolevaid andmeid. Oletame, et see fail on salvestatud meie kohaliku masina D-draivile.

Node.js-i õpetus

Sissejuhatus

Sündmused

Generators

Andmeside

Jasmiini kasutamine

Step 2) Looge tühi tühi fail nimega dataOutput.txt ja asetage see oma kohaliku masina D-kettale.

Step 3) Kirjutage allolev kood andmete edastamiseks failist datainput.txt faili dataOutput.txt.

Torud failis Node.js

var fs = require("fs");
var readStream = fs.createReadStream("D://datainput.txt");
var writeStream = fs.createWriteStream("D://dataOutput.txt");
readStream.pipe(writeStream);

Code Selgitus:-

  1. Esmalt loome oma datainput.txt failile lugemisvoo, mis sisaldab kõiki meie andmeid, mis tuleb uude faili üle kanda.
  2. Seejärel peame oma failile dataOutput.txt looma "kirjutusvoo", mis on meie tühi fail ja mis on failist datainput.txt andmete edastamise sihtkoht.
  3. Seejärel kasutame käsku toru, et edastada andmed lugemisvoost kirjutamisvoogu. Torukäsk võtab kõik lugemisvoogu saabuvad andmed ja suunab need kirjutusvoogu.

Kui avate nüüd faili dataOutput.txt, näete kõiki andmeid, mis olid failis datainput.txt.

Voo sündmused ja vasturõhk Node.js-is

Nagu eespool näidatud, peidab pipe() kutsumine kaks mastaabis olulist mehaanikat: iga voo tekitatavad sündmused ja vasturõhusüsteem, mis takistab kiirel allikal aeglast sihtkohta üle koormamast.

  • andmed: loetava voo poolt iga kord, kui uus tükk on saadaval, väljastatakse.
  • lõpp: väljastatakse pärast seda, kui loetav voog on edastanud oma viimase tüki.
  • lõpetama: kirjutatava voo poolt väljastatud, kui kõik järjekorras olevad andmed on tühjendatud.
  • viga: Edastab mõlema vootüübi poolt rikke korral; käsitle seda alati või protsess jookseb kokku.

Allolev näide kuulab kõiki nelja sündmust, hallates samal ajal käsitsi vasturõhku – sama käitumist pakub pipe() automaatselt.

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);
});

Vasturõhk tekib siis, kui loetav voog toodab andmeid kiiremini, kui kirjutatav voog neid tarbida suudab. Meetod write() tagastab väärtuse „väär”, kui puhver täitub, seega ülaltoodud kood peatab allika, kuni sihtkoht väljastab tühjendussündmuse, mis annab märku, et jätkamine on ohutu. pipe() sooritab selle tsükli automaatselt.

⚠ Näpunäide: Tootmises keskkonnas eelista käsitsi loodud pipe() ahelale voogmooduli pipeline() funktsiooni, kuna see edastab iga voo vead ja sulgeb failikäepidemed automaatselt.

Sündmused rakenduses Node.js

Vood on üks näide Node.js-i laiemast sündmustepõhisest disainist. Ülejäänud artikkel vaatleb sündmuste üldist toimimist, kasutades samu EventEmitter klassi, millele vood sisemiselt toetuvad.

Sündmused on üks Node.js-i põhimõisteid ja mõnikord nimetatakse Node.js-i sündmustepõhiseks raamistikuks.

Põhimõtteliselt on sündmus midagi, mis juhtub. Näiteks kui luuakse ühendus andmebaasiga, siis käivitatakse andmebaasiühenduse sündmus. Sündmuspõhise programmeerimise eesmärk on luua funktsioone, mis käivituvad konkreetsete sündmuste käivitamisel.

Vaatame põhinäidet sündmuse määratlemiseks failis Node.js.

Loome sündmuse nimega 'data_received'. Kui see sündmus käivitatakse, saadetakse konsooli tekst "andmed vastu võetud".

Sündmused rakenduses Node.js

var events = require('events');
var eventEmitter = new events.EventEmitter();
eventEmitter.on('data_received', function() {
    console.log('data received succesfully.');
});

eventEmitter.emit('data_received'); 

Code Selgitus:-

  1. Sündmuste mooduli kaasamiseks kasutage funktsiooni Nõua. Selle mooduli abil saate luua Node.js-is sündmusi.
  2. Looge uus sündmuste saatja. Seda kasutatakse sündmuse sidumiseks, mis meie puhul on "data_received" tagasihelistamisfunktsiooniga, mis on määratletud etapis 3.
  3. Määratleme sündmusepõhise funktsiooni, mis ütleb, et kui sündmus "data_received" käivitatakse, peaksime konsooli väljastama teksti "data_received".
  4. Lõpuks on meil oma sündmuse käsitsi käivitamine, kasutades funktsiooni eventEmiter.emit. See käivitab sündmuse data_received.

Programmi käivitamisel saadetakse konsooli tekst "andmed vastu võetud", nagu allpool näidatud.

Sündmused rakenduses Node.js

Sündmuste väljastamine

Lisaks sündmuste emiteerimisele ja kuulamisele pakub Node.js lisameetodeid kuulajate registreerimise ja kontrollimise kontrollimiseks.

Sündmuste määratlemisel on sündmuste jaoks erinevad meetodid, mida saab kutsuda. See teema keskendub igaühe üksikasjalikule vaatamisele.

  1. Ühekordsed sündmuste käsitlejad

Mõnikord võite olla huvitatud sündmusele reageerimisest alles siis, kui see toimub. Sellistes olukordades saate kasutada üks kord () meetodit.

Vaatame, kuidas saame sündmuste käitlejate jaoks ühekordset meetodit kasutada.

Sündmuste väljastamine

Code Selgitus:-

  1. Siin kasutame meetodit "once", et öelda, et sündmuse "data_received" puhul tuleks tagasihelistamise funktsiooni käivitada ainult üks kord.
  2. Siin käivitame käsitsi sündmuse 'data_received'.
  3. Kui sündmus 'data_received' uuesti käivitatakse, ei juhtu seekord midagi. Selle põhjuseks on esimene samm, kus me ütlesime, et sündmust saab käivitada ainult üks kord.

Kui kood on õigesti käivitatud, on logi väljundiks 'data_received edukalt'. See teade kuvatakse konsoolis ainult üks kord.

  1. Sündmuste kuulajate kontrollimine

Sündmuse emitteril võib igal ajal oma eluea jooksul olla null või enam kuulajat. Iga sündmuse tüübi kuulajaid saab kontrollida mitmel viisil.

Kui teid huvitab ainult lisatud kuulajate arvu määramine, siis ärge vaadake kaugemale kui meetod EventEmitter.listenerCount().

(Märge: Kuulajad on olulised, sest põhiprogramm peaks teadma, kas sündmusele lisatakse kuulajaid käigu pealt, vastasel juhul tekib programmis tõrkeid, kuna helistatakse lisakuulajatele.)

Sündmuste väljastamine

Code Selgitus:-

  1. Me defineerime eventEmitteri tüübi, mis on vajalik sündmustega seotud meetodite kasutamiseks.
  2. Seejärel määratleme objekti nimega emitter, mida kasutatakse sündmuste käitlejate määratlemiseks.
  3. Loome 2 sündmuste käitlejat, mis põhimõtteliselt ei tee midagi. See on meie näite jaoks lihtne, et näidata, kuidas kuularCount meetod töötab.
  4. Nüüd, kui käivitate meie sündmuse data_received meetodi listenerCount, saadab see konsooli logis sellele sündmusele lisatud sündmuste kuulajate arvu.

Kui kood on õigesti käivitatud, kuvatakse konsooli logis väärtus 2.

  1. Uus kuulaja sündmus

Iga kord, kui registreeritakse uus sündmuste käitleja, väljastab sündmuse saatja uue kuulaja sündmuse. Seda sündmust kasutatakse uute sündmuste töötlejate tuvastamiseks. Tavaliselt kasutate newListeneri sündmust siis, kui peate eraldama ressursse või sooritama mõne toimingu iga uue sündmusekäsitleja jaoks.

Sündmuste väljastamine

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 Selgitus:-

  1. Loome sündmuse "newListener" jaoks uut sündmuste töötlejat. Nii et iga kord, kui registreeritakse uus sündmuste töötleja, kuvatakse konsoolis tekst "Lisatud kuulaja" + sündmuse nimi.
  2. Siin kirjutame konsooli teksti "Lisatud kuulaja" + sündmuse nime iga registreeritud sündmuse kohta.
  3. Määratleme oma sündmusele 'data_received' kaks sündmuste töötlejat.

Kui ülaltoodud kood on õigesti käivitatud, kuvatakse konsoolis allolev tekst. See näitab lihtsalt, et 'newListener' sündmuste käitleja käivitati kaks korda.

Data_received sündmuste kuulaja on lisatud

Data_received sündmuste kuulaja on lisatud

KKK

fs.readFile() laadib enne tagastamist terve faili mällu, samas kui fs.createReadStream() edastab faili saabumisel väikeste tükkidena. Vood kasutavad suurte failide puhul palju vähem mälu ja lasevad töötlemisel alata enne lugemise lõppu.

Jah. Kutsu .pipe() funktsiooni iga sihtkoha kohta üks kord, näiteks readStream.pipe(destinationA), millele järgneb readStream.pipe(destinationB). Node.js edastab igale sihtkohale samad tükid ja iga kirjutatav voog haldab endiselt oma vasturõhku iseseisvalt.

Jah. Suuna loetav voog läbi teisendusvoo, näiteks zlib.createGzip(), seejärel kirjutatavasse voogu: readStream.pipe(zlib.createGzip()).pipe(writeStream). Fail tihendatakse voogesituse ajal ilma kogu faili mällu laadimata.

Nad saavad kiiresti toimiva readStreami mustandit ja standardvormingut edastada, kuid sageli jätavad nad veasündmuse käitleja ja vasturõhu käsitlemise välja. Enne tootmiskeskkonnas kasutamist vaadake alati tehisintellekti loodud vookood üle mõlema lünga suhtes.

Nad võivad pakkuda välja tõenäolisi põhjuseid, näiteks puuduvat äravoolukuulajat või käsitlemata veasündmust, kuid tegeliku põhjuse kinnitamiseks on siiski vaja voo olekut ja rakenduse logisid käsitsi kontrollida.

Võta see postitus kokku järgmiselt: