Suche…


Parameter

Parameter Definition
Lesbarer Stream Typ des Streams, aus dem Daten gelesen werden können
Beschreibbarer Stream Typ des Streams, in den Daten geschrieben werden können
Duplex-Stream Typ des Streams, der sowohl lesbar als auch schreibbar ist
Stream umwandeln Typ des Duplex-Streams, der Daten konvertieren kann, während sie gelesen und dann geschrieben werden

Daten aus Textdatei mit Streams lesen

Die E / A im Knoten ist asynchron, sodass bei der Interaktion mit der Festplatte und dem Netzwerk Callbacks an Funktionen übergeben werden. Sie könnten versucht sein, Code zu schreiben, der eine Datei von der Festplatte abruft:

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

Dieser Code funktioniert, ist aber sperrig und puffert die gesamte Datei data.txt für jede Anforderung in den Speicher, bevor das Ergebnis an die Clients zurückgeschrieben wird. Wenn data.txt sehr groß ist, kann Ihr Programm viel Speicherplatz beanspruchen, da es gleichzeitig viele Benutzer bedient, insbesondere für Benutzer mit langsamen Verbindungen.

Die Benutzererfahrung ist ebenfalls schlecht, da Benutzer warten müssen, bis die gesamte Datei in den Speicher Ihres Servers gepuffert ist, bevor sie Inhalte empfangen können.

Glücklicherweise sind beide Argumente (req, res) Streams, was bedeutet, dass wir dies mit fs.createReadStream () anstelle von fs.readFile () viel besser schreiben können:

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

Hier sorgt .pipe () für das Abhören von 'data' und 'end' Ereignissen aus dem fs.createReadStream (). Dieser Code ist nicht nur sauberer, sondern die Datei "data.txt" wird jetzt für jeden einzelnen Block sofort in die Clients geschrieben, sobald sie von der Festplatte empfangen werden.

Piping-Streams

Lesbare Streams können zu "Pipes" oder zu schreibbaren Streams verbunden werden. Dadurch wird der Datenfluss vom Quellstream zum Zielstream ohne großen Aufwand durchgeführt.

var fs = require('fs')

var readable = fs.createReadStream('file1.txt')
var writable = fs.createWriteStream('file2.txt')

readable.pipe(writable) // returns writable

Wenn beschreibbare Streams auch lesbare Streams sind, dh wenn sie Duplex- Streams sind, können Sie sie an andere beschreibbare Streams weiterleiten.

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')

Lesbare Streams können auch in mehrere Streams geleitet werden.

var readable = fs.createReadStream('source.css')
readable.pipe(zlib.createGzip()).pipe(fs.createWriteStream('output.css.gz'))
readable.pipe(fs.createWriteStream('output.css')

Beachten Sie, dass Sie synchron (gleichzeitig) an die Ausgabeströme weiterleiten müssen, bevor Daten "fließen". Andernfalls können unvollständige Daten gestreamt werden.

Beachten Sie auch, dass Stream-Objekte error ausgeben können. Vergewissern Sie sich, dass Sie diese Ereignisse in jedem Stream nach Bedarf verantwortungsbewusst behandeln:

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)

Erstellen Sie einen eigenen lesbaren / beschreibbaren Stream

Wir werden Stream-Objekte sehen, die von Modulen wie FS usw. zurückgegeben werden. Was aber, wenn wir unser eigenes Streamable-Objekt erstellen möchten?

Um ein Stream-Objekt zu erstellen, müssen Sie das von NodeJs bereitgestellte Stream-Modul verwenden

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

Dies gibt uns unseren eigenen benutzerdefinierten Stream. wir können alles innerhalb der _write- Funktion implementieren . Die obige Methode funktioniert in NodeJs 4.xx-Version, aber in NodeJs 6.x ES6 haben Klassen eingeführt, weshalb sich die Syntax geändert hat. Unten ist der Code für die 6.x-Version von NodeJs

    const Writable = require('stream').Writable;
    
    class MyWritable extends Writable {
      constructor(options) {
        super(options);
      }
    
      _write(chunk, encoding, callback) {
        console.log(chunk);
      }
    }

Warum Streams?

Schauen wir uns die folgenden zwei Beispiele an, um den Inhalt einer Datei zu lesen:

Die erste, die eine asynchrone Methode zum Lesen einer Datei verwendet und eine Rückruffunktion bereitstellt, die aufgerufen wird, sobald die Datei vollständig in den Speicher eingelesen ist:

fs.readFile(`${__dirname}/utils.js`, (err, data) => {
  if (err) {
    handleError(err);
  } else {
    console.log(data.toString());
  }
})

Und die zweite, die streams verwendet, um den Inhalt der Datei Stück für Stück zu lesen:

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

Es ist erwähnenswert, dass beide Beispiele dasselbe tun . Was ist dann der Unterschied?

  • Der erste ist kürzer und sieht eleganter aus
  • Mit der zweiten können Sie die Datei bearbeiten, während sie gelesen wird (!).

Wenn die Dateien, mit denen Sie arbeiten, klein sind, gibt es keinen wirklichen Effekt bei der Verwendung von streams , aber was passiert, wenn die Datei groß ist? (so groß, dass es 10 Sekunden dauert, um es in den Speicher zu lesen)

Ohne streams Sie warten und absolut nichts tun (es sei denn, Ihr Prozess erledigt anderes), bis die 10 Sekunden vergangen sind und die Datei vollständig gelesen ist. Erst dann können Sie die Datei verarbeiten.

Mit streams Sie den Inhalt der Datei Stück für Stück, sobald sie verfügbar sind. Dadurch können Sie die Datei verarbeiten, während sie gelesen wird.


Das obige Beispiel veranschaulicht nicht, wie streams für Arbeiten verwendet werden können, die beim Callback-Modus nicht ausgeführt werden können. Schauen wir uns also ein anderes Beispiel an:

Ich möchte eine herunterladen gzip - Datei, entpacken und seinen Inhalt auf die Festplatte speichern. In Anbetracht der url der Datei müssen Sie url tun:

  • Laden Sie die Datei herunter
  • Entpacke die Datei
  • Speichern Sie es auf der Festplatte

Hier ist eine [kleine Datei] [1], die in meinem S3 Speicher gespeichert ist. Der folgende Code führt das oben auf die Rückrufweise aus.

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

So sieht es mit streams :

s3.getObject({Bucket: 'some-bucket', Key: 'tweets.gz'}).createReadStream()
  .pipe(zlib.createGunzip())
  .pipe(fs.createWriteStream(`${__dirname}/tweets.json`));

// 1204 milliseconds

Ja, bei kleinen Dateien geht es nicht schneller - die getestete Datei 80KB . Das Testen einer größeren Datei mit 71MB MB ( 382MB MB entpackt) zeigt, dass die streams Version viel schneller ist

  • Es dauerte 20925 Millisekunden zum Download 71MB , entpacken und dann schreiben 382MB auf der Festplatte - mit der Callback Mode.
  • Im Vergleich dazu dauerte es 13434 Millisekunden, um dasselbe bei Verwendung der streams Version zu tun (35% schneller, für eine nicht so große Datei).


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow