Node.js - Streams

What are Streams?

Một dòng (stream) là một tập hợp dữ liệu. Tuy nhiên, khác với một mảng (array) hoặc một chuỗi (string), toàn bộ dữ liệu trong một đối tượng dòng không được lưu trữ cùng một lúc trong bộ nhớ. Thay vào đó, một khối dữ liệu đơn lẻ từ dòng được đưa vào bộ nhớ, từng lần một. Điều này làm cho các dòng trở nên hiệu quả hơn. Các ứng dụng Node.js rất phù hợp cho việc phát triển các ứng dụng truyền dữ liệu (data streaming).

Types of streams

Node.js xử lý bốn loại luồng cơ bản −

  • Writable − các luồng mà dữ liệu có thể được ghi vào.

  • Readable − các luồng từ đó dữ liệu có thể được đọc.

  • Duplex − các luồng vừa có thể đọc vừa có thể ghi.

  • Transform − Các luồng duplex có thể sửa đổi hoặc chuyển đổi dữ liệu khi nó được ghi và đọc.

Mỗi loại Stream là một phiên bản của EventEmitter và phát ra nhiều sự kiện tại các thời điểm khác nhau. Ví dụ, một số sự kiện thường được sử dụng là −

  • data − Sự kiện này được kích hoạt khi có dữ liệu có sẵn để đọc.

  • end − Sự kiện này được kích hoạt khi không còn dữ liệu nào để đọc.

  • error − Sự kiện này được kích hoạt khi có bất kỳ lỗi nào xảy ra trong việc nhận hoặc ghi dữ liệu.

  • finish − Sự kiện này được kích hoạt khi tất cả dữ liệu đã được ghi vào hệ thống cơ sở.

Các ví dụ trong chương này sử dụng một tệp có tên là input.text với dữ liệu sau trong đó.

Tutorials Point is giving self learning content
to teach the world in simple and easy way!!!!!

Readable Stream

Đối tượng file hoạt động như một luồng từ đó dữ liệu có thể được đọc theo từng khối có kích thước cụ thể. Trong ví dụ dưới đây, chúng ta gọi hàm createReadStream() từ mô-đun fs để đọc dữ liệu từ một tệp đã cho. Sự kiện on của luồng có thể đọc được thu thập nội dung tệp cho đến khi sự kiện end được kích hoạt.

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

// Create a readable stream
var readerStream = fs.createReadStream('input.txt');

// Set the encoding to be utf8. 
readerStream.setEncoding('UTF8');

// Handle stream events --> data, end, and 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("Program Ended");

Lưu đoạn kịch bản trên với tên là main.js. Chạy ứng dụng Node.js trên. Nó sẽ hiển thị nội dung của tệp input.text.

Writable Stream

Hàm createWriteStream() từ mô-đun fs tạo ra một đối tượng luồng ghi. Phương thức write() của nó lưu trữ dữ liệu vào tệp được cung cấp cho hàm createWriteStream() dưới dạng tham số.

Lưu đoạn mã sau với tên là main.js.

var fs = require("fs");
var data = `Tutorials Point is giving self learning content
to teach the world in simple and easy way!!!!!`;

// Create a writable stream
var writerStream = fs.createWriteStream('output.txt');

// Write the data to stream with encoding to be utf8
writerStream.write(data,'UTF8');

// Mark the end of file
writerStream.end();

// Handle stream events --> finish, and error
writerStream.on('finish', function() {
   console.log("Write completed.");
});

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

console.log("Program Ended");

Bây giờ hãy mở file output.txt được tạo trong thư mục hiện tại của bạn để kiểm tra xem nó có chứa dữ liệu đã cho hay không.

Piping the Streams

Piping là một cơ chế mà chúng ta cung cấp đầu ra của một luồng như đầu vào cho một luồng khác. Nó thường được sử dụng để lấy dữ liệu từ một luồng và chuyển đầu ra của luồng đó đến một luồng khác. Không có giới hạn nào cho các thao tác piping. Bây giờ chúng ta sẽ trình bày một ví dụ về piping để đọc từ một tệp và ghi nó vào một tệp khác.

Tạo một tệp js có tên main.js với mã sau −

var fs = require("fs");

// Create a readable stream
var readerStream = fs.createReadStream('input.txt');

// Create a writable stream
var writerStream = fs.createWriteStream('output.txt');

// Pipe the read and write operations
// read input.txt and write data to output.txt
readerStream.pipe(writerStream);

console.log("Program Ended");

Bây giờ hãy chạy file main.js để xem kết quả −

node main.js

Xác minh đầu ra.

Program Ended

Mở file output.txt được tạo trong thư mục hiện tại của bạn; nó nên chứa các nội dung sau −

Tutorials Point is giving self learning content
to teach the world in simple and easy way!!!!!

Chaining the Streams

Chaining là một cơ chế để kết nối đầu ra của một luồng này với một luồng khác và tạo ra một chuỗi các thao tác luồng. Nó thường được sử dụng với các thao tác piping. Bây giờ, chúng ta sẽ sử dụng piping và chaining để đầu tiên nén một tệp và sau đó giải nén tệp đó.

Tạo một tệp js có tên main.js với mã sau −

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

// Compress the file input.txt to input.txt.gz
fs.createReadStream('input.txt')
   .pipe(zlib.createGzip())
   .pipe(fs.createWriteStream('input.txt.gz'));
  
console.log("File Compressed.");

Bây giờ hãy chạy file main.js để xem kết quả −

node main.js

Xác minh đầu ra.

File Compressed.

Bạn sẽ thấy rằng file input.txt đã được nén và một file input.txt.gz đã được tạo trong thư mục hiện tại. Bây giờ, hãy thử giải nén file đó bằng cách sử dụng đoạn mã sau −

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

// Decompress the file input.txt.gz to input.txt
fs.createReadStream('input.txt.gz')
   .pipe(zlib.createGunzip())
   .pipe(fs.createWriteStream('input.txt'));
  
console.log("File Decompressed.");

Bây giờ hãy chạy file main.js để xem kết quả −

node main.js

Xác minh đầu ra.

File Decompressed.