Node.js Stream

Node.js Stream ist eine abstrakte Schnittstelle zur Verarbeitung von Streaming-Daten, die in Szenarien wie Dateioperationen und Netzwerkkommunikation weit verbreitet ist.

Ein wesentlicher Vorteil der Verarbeitung von Streaming-Daten besteht darin, dass Daten während der Übertragung verarbeitet werden können, ohne darauf zu warten, dass die gesamten Daten geladen sind, wodurch Node.js große Datenmengen effizient verarbeiten kann, ohne übermäßig viel Speicher zu verbrauchen.

Stream ist eine abstrakte Schnittstelle, und viele Objekte in Node implementieren diese Schnittstelle. Zum Beispiel ist das Request-Objekt einer HTTP-Serveranfrage ein Stream, ebenso wie stdout (Standardausgabe).

Node.js Stream ist eine Möglichkeit zum Umgang mit Datenflüssen. Es ermöglicht Ihnen, Daten auf Streaming-Weise zu verarbeiten, anstatt alle Daten auf einmal in den Speicher zu laden. Dies ist sehr nützlich für die Verarbeitung großer Datenmengen oder für eine effiziente Datenübertragung.

In Node.js gibt es vier Arten von Streams:

  • Readable- Leseoperationen.

  • Writable- Schreibbare Operationen.

  • Duplex- Lesbare und schreibbare Operationen.

  • Transform- Operationen, die Daten schreiben und dann das Ergebnis lesen.

Alle Stream-Objekte sind Instanzen von EventEmitter. Häufige Ereignisse sind:

  • data- Wird ausgelöst, wenn Daten zum Lesen verfügbar sind.

  • end- Wird ausgelöst, wenn keine Daten mehr zum Lesen vorhanden sind.

  • error- Wird ausgelöst, wenn beim Empfangen oder Schreiben ein Fehler auftritt.

  • finish- Wird ausgelöst, wenn alle Daten in das zugrunde liegende System geschrieben wurden.

Dieses Tutorial führt in gängige Stream-Operationen ein.


Daten aus einem Stream lesen

Gängige lesbare Streams umfassen Datei-Lese-Streams und Netzwerk-Anfrage-Antwort-Streams.

Erstellen Sie eine Datei input.txt mit folgendem Inhalt:

Example官网地址:www.example.com

Erstellen Sie eine Datei main.js mit folgendem Code:

Beispiel

var fs = require("fs");
var data = '';

// Einen lesbaren Stream erstellen
var readerStream = fs.createReadStream('input.txt');

// Kodierung auf utf8 setzen.
readerStream.setEncoding('UTF8');

// Stream-Ereignisse behandeln --> data, end und error
readerStream.on('data', function(chunk) {
   data += chunk;
});

readerStream.on('end',function(){
   console.log(data);
});

readerStream.on('error', function(err){
   console.log(err.stack);
});

console.log("Programmausführung abgeschlossen");

Das Ausführungsergebnis des obigen Codes ist wie folgt:

程序执行完毕
Example官网地址:www.example.com

Schreibbarer Stream

Ein schreibbarer Stream wird verwendet, um Daten an ein Ziel zu schreiben. Zu den gebräuchlichen schreibbaren Streams gehören Dateischreibstreams und Streams zum Senden von Netzwerkanfragen.

Erstellen Sie eine Datei main.js mit folgendem Code:

Beispiel

var fs = require("fs");
var data = 'Beispiel für offizielle Website-Adresse: www.example.com';

// Einen beschreibbaren Stream erstellen, der in die Datei output.txt schreibt
var writerStream = fs.createWriteStream('output.txt');

// Daten mit utf8-Kodierung schreiben
writerStream.write(data,'UTF8');

// Das Ende der Datei markieren
writerStream.end();

// Stream-Ereignisse behandeln --> finish, error
writerStream.on('finish', function() {
    console.log("Schreiben abgeschlossen.");
});

writerStream.on('error', function(err){
   console.log(err.stack);
});

console.log("Programmausführung abgeschlossen");

Das obige Programm schreibt die Daten in der Variablen data in die Datei output.txt. Das Ausführungsergebnis des Codes ist wie folgt:

$ node main.js 
程序执行完毕
写入完成。

Den Inhalt der Datei output.txt anzeigen:

$ cat output.txt 
Example官网地址:www.example.com

Duplex-Stream

Ein Duplex-Stream verfügt sowohl über Lese- als auch Schreibfähigkeiten.

Ein typischer Duplex-Stream ist ein TCP-Socket.

Beispiel

const net = require('net');

// Einen TCP-Server erstellen
const server = net.createServer((socket) => {
    console.log('Client verbunden.');

    // Client-Daten lesen
    socket.on('data', (data) => {
        console.log('Empfangene Daten:', data.toString());
    });

    // Daten an den Client senden
    socket.write('Hallo, Client!\n');

    // Auf das close-Ereignis lauschen
    socket.on('end', () => {
        console.log('Client getrennt.');
    });
});

server.listen(3000, () => {
    console.log('Server lauscht auf Port 3000.');
});

Transform-Stream

Ein Transform-Stream ist eine spezielle Art von Duplex-Stream, der Daten ändern oder transformieren kann. Häufige Transform-Streams umfassen Komprimierungs- und Dekomprimierungs-Streams.

Beispiel

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

// Einen lesbaren Stream erstellen
const readableStream = fs.createReadStream('example.txt');

// Transformations-Stream erstellen (Komprimierung)
const gzip = zlib.createGzip();

// Einen beschreibbaren Stream erstellen
const writableStream = fs.createWriteStream('example.txt.gz');

// Den lesbaren Stream an den Transformations-Stream weiterleiten, dann an den beschreibbaren Stream weiterleiten
readableStream.pipe(gzip).pipe(writableStream);

// Auf das Abschlussereignis lauschen
writableStream.on('finish', () => {
    console.log('Datei erfolgreich komprimiert.');
});

Pipe-Stream

Eine Pipe bietet einen Mechanismus, um einen Ausgabestream mit einem Eingabestream zu verbinden.

Normalerweise verwenden wir sie, um Daten von einem Stream zu beziehen und die Daten an einen anderen Stream weiterzuleiten.

Wie im obigen Bild dargestellt, vergleichen wir Dateien mit wassergefüllten Fässern, und das Wasser ist der Inhalt der Dateien. Wir verwenden eine Pipe, um die beiden Fässer zu verbinden, sodass Wasser von einem Fass in ein anderes fließt, wodurch nach und nach der Kopiervorgang großer Dateien realisiert wird.

Im folgenden Beispiel lesen wir den Inhalt einer Datei und schreiben den Inhalt in eine andere Datei.

Legen Sie den Inhalt der Datei input.txt wie folgt fest:

Example官网地址:www.example.com
管道流操作实例

Erstellen Sie eine Datei main.js mit folgendem Code:

Beispiel

var fs = require("fs");

// Einen lesbaren Stream erstellen
var readerStream = fs.createReadStream('input.txt');

// Einen beschreibbaren Stream erstellen
var writerStream = fs.createWriteStream('output.txt');

// Pipe-Lese- und Schreibvorgänge
// Den Inhalt von input.txt lesen und den Inhalt in output.txt schreiben
readerStream.pipe(writerStream);

console.log("Programmausführung abgeschlossen");

Das Ausführungsergebnis des Codes ist wie folgt:

$ node main.js 
程序执行完毕

Den Inhalt der Datei output.txt anzeigen:

$ cat output.txt 
Example官网地址:www.example.com
管道流操作实例

Verketteter Stream

Verkettung ist ein Mechanismus, um einen Ausgabestream mit einem anderen Stream zu verbinden und eine Kette mehrerer Stream-Operationen zu erstellen.

Verkettete Streams werden im Allgemeinen für Pipe-Operationen verwendet.

Als Nächstes verwenden wir Pipes und Verkettung, um Dateien zu komprimieren und zu dekomprimieren.

Erstellen Sie eine Datei compress.js mit dem folgenden Code:

Beispiel

var fs = require("fs");
var zlib = require('zlib');

// input.txt in input.txt.gz komprimieren
fs.createReadStream('input.txt')
  .pipe(zlib.createGzip())
  .pipe(fs.createWriteStream('input.txt.gz'));
 
console.log("Dateikomprimierung abgeschlossen.");

Das Ausführungsergebnis des Codes ist wie folgt:

$ node compress.js 
文件压缩完成。

Nachdem die oben genannten Operationen ausgeführt wurden, können wir sehen, dass eine komprimierte Datei input.txt.gz im aktuellen Verzeichnis erstellt wurde.

Als Nächstes dekomprimieren wir diese Datei. Erstellen Sie eine Datei decompress.js mit dem folgenden Code:

Beispiel

var fs = require("fs");
var zlib = require('zlib');

// input.txt.gz in input.txt dekomprimieren
fs.createReadStream('input.txt.gz')
  .pipe(zlib.createGunzip())
  .pipe(fs.createWriteStream('input.txt'));
 
console.log("Dateidekomprimierung abgeschlossen.");

Das Ausführungsergebnis des Codes ist wie folgt:

$ node decompress.js 
文件解压完成。

Pausieren und Fortsetzen

Ein lesbarer Stream kann das Lesen von Daten pausieren und fortsetzen.

Beispiel

const fs = require('fs');

const readableStream = fs.createReadStream('example.txt', 'utf8');

readableStream.on('data', (chunk) => {
    console.log('Empfangener Chunk:', chunk);
    readableStream.pause(); // Lesen pausieren
    setTimeout(() => {
        readableStream.resume(); // Lesen fortsetzen
    }, 1000);
});

Zerstören

Sie können einen Stream zerstören, um Ressourcen freizugeben.

Beispiel

const fs = require('fs');

const readableStream = fs.createReadStream('example.txt', 'utf8');

readableStream.on('data', (chunk) => {
    console.log('Empfangener Chunk:', chunk);
    readableStream.destroy(); // Den Stream zerstören
});
Andere Erweiterungen