Heim > Artikel > Web-Frontend > Detaillierte Erläuterung der Lese- und Schreibvorgänge für Node.js Streams-Dateien
Node.js ist von Natur aus asynchron und ereignisgesteuert, was es ideal für die Bearbeitung von I/O-bezogenen Aufgaben macht. Wenn Sie in Ihrer Anwendung E/A-bezogene Vorgänge verarbeiten, können Sie Streams in Node.js nutzen. Schauen wir uns Streams also im Detail an und verstehen, wie sie I/O-Vorgänge vereinfachen.
Was ist ein Stream?
Ein Stream ist eine Unix-Pipe, die es Ihnen ermöglicht, Daten einfach aus einer Datenquelle zu lesen und sie dann an ein anderes Ziel weiterzuleiten.
Einfach ausgedrückt ist ein Stream nichts Besonderes, sondern lediglich ein EventEmitter, der einige Methoden implementiert. Abhängig von der Implementierung kann ein Stream zu einem lesbaren Stream (Readable), einem beschreibbaren Stream (Writable) oder einem bidirektionalen Stream (Duplex, gleichzeitig lesbar und beschreibbar) werden.
Mit lesbaren Streams können Sie Daten aus einer Datenquelle lesen, mit schreibbaren Streams können Sie Daten an ein Ziel schreiben.
Wenn Sie Node.js verwendet haben, sind Sie wahrscheinlich auf Flows gestoßen.
Beispielsweise ist in einem Node.js-HTTP-Server die Anfrage ein lesbarer Stream und die Antwort ein beschreibbarer Stream.
Möglicherweise haben Sie auch das fs-Modul verwendet, das Ihnen beim Umgang mit lesbaren und beschreibbaren Streams helfen kann.
Lassen Sie uns nun einige Grundlagen erlernen und verschiedene Arten von Streams verstehen. In diesem Artikel werden lesbare Streams und bidirektionale Streams behandelt. Diese gehen über den Rahmen dieses Artikels hinaus und werden nicht behandelt.
Lesbare Streams
Wir können lesbare Streams verwenden, um Daten aus einer Datenquelle zu lesen. Diese Datenquelle kann alles sein, beispielsweise eine Datei im System, ein Puffer im Speicher oder sogar andere Streams. Da Streams EventEmitter sind, senden sie Daten mit verschiedenen Ereignissen. Wir werden diese Ereignisse nutzen, um den Ablauf zum Laufen zu bringen.
Daten aus dem Stream lesen
Der beste Weg, Daten aus dem Stream zu lesen, besteht darin, das Datenereignis abzuhören und eine Rückruffunktion hinzuzufügen. Wenn Daten einfließen, sendet der lesbare Stream das Datenereignis und die Rückruffunktion wird ausgelöst. Schauen Sie sich den folgenden Codeausschnitt an:
var fs = require('fs'); var readableStream = fs.createReadStream('file.txt'); var data = ''; var readableStream.on('data', function(chunk){ data += chunk; }); readableStream.on('end', function(){ console.log(data); });
fs.createReadStream liefert Ihnen einen lesbaren Stream.
Am Anfang ist dieser Stream nicht dynamisch. Wenn Sie einen Ereignis-Listener für Daten und eine Rückruffunktion hinzufügen, wird es flüssig. Danach liest es ein kleines Datenelement und übergibt es an Ihre Rückruffunktion.
Der Implementierer des Streams bestimmt, wie oft das Datenereignis ausgelöst wird. Beispielsweise löst eine HTTP-Anfrage das Datenereignis aus, wenn einige KB Daten gelesen werden. Wenn Sie Daten aus einer Datei lesen, können Sie sich dafür entscheiden, das Datenereignis auszulösen, wenn eine Zeile gelesen wird.
Wenn keine Daten zum Lesen vorhanden sind (wenn das Ende der Datei gelesen wird), sendet der Stream das Endereignis. Im obigen Beispiel haben wir dieses Ereignis abgehört und die Daten gedruckt, als wir mit dem Lesen der Datei fertig waren.
Es gibt eine andere Möglichkeit, einen Stream zu lesen. Sie müssen lediglich die Methode read() auf der Stream-Instanz aufrufen, bevor Sie das Ende der Datei lesen. Die Methode
var fs = require('fs'); var readableStream = fs.createReadStream('file.txt'); var data = ''; var chunk; readableStream.on('readable', function(){ while ((chunk = readableStream.read()) != null) { data += chunk; } }); readableStream.on('end', function(){ console.log(data); });
read() liest Daten aus dem internen Puffer. Wenn keine Daten zum Lesen vorhanden sind, wird null zurückgegeben.
Also prüfen wir in der while-Schleife, ob read() null zurückgibt, und wenn es null zurückgibt, beenden wir die Schleife.
Es ist zu beachten, dass das lesbare Ereignis ausgelöst wird, wenn wir Daten aus dem Stream lesen können.
Kodierung festlegen
Standardmäßig ist das, was Sie aus dem Stream lesen, ein Pufferobjekt. Wenn Sie Zeichenfolgen lesen möchten, ist dies nicht für Sie geeignet. Daher können Sie die Codierung des Streams festlegen, indem Sie Readable.setEncoding() wie im folgenden Beispiel aufrufen:
var fs = require('fs'); var readableStream = fs.createReadStream('file.txt'); var data = ''; readableStream.setEncoding('utf8'); readableStream.on('data', function(chunk){ data += chunk; }); readableStream.on('end', function(){ console.log(data); });
Im obigen Beispiel legen wir die Codierung des Streams und der Daten auf utf8 fest wird in utf8 geparst, der Block in der Rückruffunktion wird ein String sein.
Piping
Piping ist ein großartiger Mechanismus, der es Ihnen ermöglicht, Daten aus einer Datenquelle zu lesen und an das Ziel zu schreiben, ohne den Status des Streams selbst verwalten zu müssen. Schauen wir uns zunächst das folgende Beispiel an:
var fs = require('fs'); var readableStream = fs.createReadStream('file1.txt'); var writableStream = fs.createWriteStream('file2.txt'); readableStream.pipe(writableStream);
Das obige Beispiel verwendet die Methode „pipe()“, um den Inhalt von Datei1 in Datei2 zu schreiben. Da pipe() den Datenfluss für Sie verwaltet, müssen Sie sich keine Gedanken über die Geschwindigkeit des Datenflusses machen. Dies macht Pipe() sehr prägnant und einfach zu verwenden.
Es ist zu beachten, dass pipe() den Zielstream zurückgibt, sodass Sie problemlos mehrere Streams verknüpfen können!
Verkettung
Angenommen, Sie haben ein Archiv und möchten es entpacken. Es gibt viele Möglichkeiten, diese Aufgabe zu erfüllen. Aber der einfachste Weg ist die Verwendung von Pipes und Links:
var fs = require('fs'); var zlib = require('zlib'); fs.createReadStream('input.txt.gz') .pipe(zlib.createGunzip()) .pipe(fs.createWriteStream('output.txt'));
Zuerst erstellen wir einen lesbaren Stream über input.txt.gz und lassen ihn dann zlib.createGunzip() streamen, wodurch er dekomprimiert wird Inhalt. Schließlich fügen wir einen beschreibbaren Stream hinzu, um den dekomprimierten Inhalt in eine andere Datei zu schreiben.
Andere Methoden
Wir haben einige wichtige Konzepte in lesbaren Streams besprochen. Hier sind einige Methoden, die Sie kennen müssen:
1.Readable.pause() – Diese Methode unterbricht den Fluss des Streams. Mit anderen Worten: Das Datenereignis wird nicht mehr ausgelöst.
2.Readable.resume() – Diese Methode ist das Gegenteil der oben genannten und setzt den angehaltenen Stream fort.
3.Readable.unpipe() – Diese Methode entfernt das Ziel. Wenn ein Argument übergeben wird, wird der lesbare Stream von einem bestimmten Ziel gestoppt, andernfalls werden alle Ziele entfernt.
可写流 (Writable Streams)
可写流让你把数据写入目的地。就像可读流那样,这些也是 EventEmitter ,它们也会触发不同的事件。我们来看看可写流中会触发的事件和方法吧。
写入流
要把数据写如到可写流中,你需要在可写流实例中调用 write() 方法,看看下面的例子:
var fs = require('fs'); var readableStream = fs.createReadStream('file1.txt'); var writableStream = fs.createWriteStream('file2.txt'); readableStream.setEncoding('utf8'); readableStream.on('data', function(chunk){ writableStream.write('chunk'); });
上面的代码非常简单,它只是从输入流中读取数据,然后用 write() 写入到目的地中。
这个方法返回一个布尔值来表示写入是否成功。如果返回的是 true 那表示写入成功,你可以继续写入更多的数据。 如果是 false ,那意味着发生了什么错误,你现在不能继续写入了。可写流会触发一个 drain 事件来告诉你你可以继续写入数据。
写完数据后
当你不需要在写入数据的时候,你可以调用 end() 方法来告诉流你已经完成写入了。假设 res 是一个 HTTP response 对象,你通常会发送响应给浏览器:
res.write('Some Data!!');
res.end();
当 end() 被调用时,所有数据会被写入,然后流会触发一个 finish 事件。注意在调用 end() 之后,你就不能再往可写流中写入数据了。例如下面的代码就会报错:
res.write('Some Data!!');
res.end();
res.write('Trying to write again'); //Error !
这里有一些和可写流相关的重要事件:
1.error – 在写入或链接发生错误时触发
2.pipe – 当可读流链接到可写流时,这个事件会触发
3.unpipe – 在可读流调用 unpipe 时会触发
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持PHP中文网。
更多Node.js Streams文件读写操作详解相关文章请关注PHP中文网!