Hướng dẫn createwritestream nodejs - createwritestream nodejs

1. Stream là gì?

Stream là tập hợp dữ liệu - giống như mảng hoặc chuỗi. Sự khác biệt là các Stream có thể không có sẵn cùng một lúc và kích thước của chúng cũng không nhất thiết phải vừa với bộ nhớ (sẽ không gây ra tràn bộ nhớ).

Điều này làm cho các Stream thực sự rất hữu ích khi làm việc với dữ liệu lớn hoặc dữ liệu đã được chia nhỏ (chunk) truyền từ ngoài vào.

Tuy nhiên, Stream không chỉ để về làm việc với dữ liệu lớn. Chúng cũng cung cấp khả năng kết hợp code.

Giống như chúng ta có thể gõ các lệnh linux bằng cách kết hợp các lệnh Linux nhỏ hơn, chúng ta có thể làm chính xác như vậy trong Nodejs khi sử dụng Stream bằng cách sử dụng phương thức pipe().pipe().

Có bốn loại luồng cơ bản trong Node.js: Readable, Writable, Duplex, and Transform.Readable, Writable, Duplex, and Transform.

Readable sử dụng cho hoạt động đọc, ví dụ đó là phương thức fs.createReadStream. sử dụng cho hoạt động đọc, ví dụ đó là phương thức fs.createReadStream.

Writable sử dụng cho hoạt động ghi. , ví dụ đó là phương thức fs.createWriteStream. sử dụng cho hoạt động ghi. , ví dụ đó là phương thức fs.createWriteStream.

Duplex có thể đọc và ghi được, ví dụ như TCP socket. có thể đọc và ghi được, ví dụ như TCP socket.

Transform về cơ bản là Duplex có thể được sử dụng để sửa đổi hoặc biến đổi dữ liệu khi nó được ghi và đọc. Một ví dụ về điều đó là zlib.createGzip để nén dữ liệu bằng gzip. Bạn có thể nghĩ về một Transform là một function trong đó đầu vào là phần stream có thể ghi và đầu ra là phần stream có thể đọc được. về cơ bản là Duplex có thể được sử dụng để sửa đổi hoặc biến đổi dữ liệu khi nó được ghi và đọc. Một ví dụ về điều đó là zlib.createGzip để nén dữ liệu bằng gzip. Bạn có thể nghĩ về một Transform là một function trong đó đầu vào là phần stream có thể ghi và đầu ra là phần stream có thể đọc được.

2. Phương thức Pipe

Ví dụ khi sử dụng pipe

readableSrc.pipe(writableDest)

Trong dòng code đơn giản này, chúng ta nối (pipe) đầu ra của Readable Stream - nguồn dữ liệu, với đầu vào của Writable Stream - đích. Tất nhiên, cả hai đều có thể là Duplex / Transform Stream.

Trong Linux, cơ chế này tương đương với command

var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
6

Nói tóm lại, Pipe là một kỹ thuật. Với kỹ thuật này, chúng ta cung cấp kết quả đầu ra của một Stream để làm dữ liệu đầu vào cho một Stream khác. Không có giới hạn nào về hoạt động này, tức là quá trình trên vẫn có thể tiếp tụcPipe là một kỹ thuật. Với kỹ thuật này, chúng ta cung cấp kết quả đầu ra của một Stream để làm dữ liệu đầu vào cho một Stream khác. Không có giới hạn nào về hoạt động này, tức là quá trình trên vẫn có thể tiếp tục

var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
7

3. Lợi ích khi sử dụng Stream khi xử lý dữ liệu lớn

Giả sử chúng ta sử dụng phương thức readFile của Nodejs để đọc file sau đó ghi vào 1 file khác

var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);

Trong trường hợp này, trước khi thực hiện ghi file, chúng ta đã đẩy toàn bộ dữ liệu của file đọc được vào bộ nhớ, điều này rất dễ gây tràn bộ nhớ và kể cả có không gây tràn bộ nhớ thì việc lãng phí bộ nhớ như vậy cũng là một cách làm không hiệu quả.

Sử dụng Stream và pipe:

var fs = require('fs');
 
var readStream = fs.createReadStream('test.txt');
var writeStream = fs.createWriteStream('write_file.txt');

readStream.setEncoding('utf8');
readStream.pipe(writeStream);

Khi sử dụng pipe, thì mặc định,

var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
8 sẽ chia nhỏ lượng dữ liệu để truyền vào
var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
9 , mặc định là 64*1024 (64KB)pipe, thì mặc định,
var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
8 sẽ chia nhỏ lượng dữ liệu để truyền vào
var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
9 , mặc định là 64*1024 (64KB)

Một cách khác để ghi mà không sử dụng pipe :

var fs = require('fs');
 
var readStream = fs.createReadStream('big.file', { highWaterMark: 20 * 1024 });
readStream.setEncoding('utf8');
var writeStream = fs.createWriteStream('write_file.txt', {'flags':'a'});

readStream.on('data', function(chunk) {
   writeStream.write(chunk);
});

Ở đây chúng ta chia nhỏ dữ liệu theo chunk là 20*1024. pipe thường dùng để truyền thẳng trực tiếp dữ liệu từ Stream này tới Stream khác nên sẽ không thể tùy biến được trong quá trình đó. Vì vậy chúng ta chỉ nên sử dụng pipe khi không cần xử lý events.

Nguồn tham khảo: https://www.udemy.com/course/learn-node-js-complete-from-very-basics-to-advance

https://www.freecodecamp.org/news/node-js-streams-everything-you-need-to-know-c9141306be93/

Streams trong NodeJS là gì ?

Streamstrong NodeJS là một collections của dữ liệu giống như strings hay arrays, sự khác nhau duy nhất đó là các streams không tồn tại cùng một lúc. Điều khiến streams thực sự mạnh đó là khả năng làm việc khi xử lý với dữ liệu lớn (big data) hay nguồn dữ liệu đến từ nguồn bên ngoài.trong NodeJS là một collections của dữ liệu giống như strings hay arrays, sự khác nhau duy nhất đó là các streams không tồn tại cùng một lúc. Điều khiến streams thực sự mạnh đó là khả năng làm việc khi xử lý với dữ liệu lớn (big data) hay nguồn dữ liệu đến từ nguồn bên ngoài.

Streams không chỉ dừng lại ở việc xử lý dữ liệu, nó còn đem lại khả năng kết hợp code một cách tuyệt vời, giống như khi kết hợp các câu lệnh lunix với nhau thành một câu lệnh duy nhất.

Có rất nhiều các module của Nodejs thực hiện dựa trên hơi hướng của streams như:

Hướng dẫn createwritestream nodejs - createwritestream nodejs

Streams cho phép bạn đọc dữ liệu từ một nguồn hoặc viết dữ liệu tới một đích đến. Trong NodeJS, có 4 loại streams khác nhau:cho phép bạn đọc dữ liệu từ một nguồn hoặc viết dữ liệu tới một đích đến. Trong NodeJS, có 4 loại streams khác nhau:

  1. Readable: đây là loại streams chỉ dùng để đọc..đây là loại streams chỉ dùng để đọc..
  2. Writable : đây là loại streams chỉ dùng để ghi..đây là loại streams chỉ dùng để ghi..
  3. Duplex : sử dụng cả 2 đọc và ghi.: sử dụng cả 2 đọc và ghi.
  4. Transform : một loại của Duplex nhưng khác nhau bởi kết quả của đầu ra dựa vào đầu vào.một loại của Duplex nhưng khác nhau bởi kết quả của đầu ra dựa vào đầu vào.

Mỗi streams đều được cấp một EventEmitter cho phép chúng ta bắt sự kiện theo từng thời điểm cụ thể. Sau đây là một vài sự kiên hay dùng :

  • data: sự kiện này được kích hoạt khi dữ liệu được đọcsự kiện này được kích hoạt khi dữ liệu được đọc
  • end: sự kiện này được kích hoạt khi không còn dữ liệu để đọcsự kiện này được kích hoạt khi không còn dữ liệu để đọc
  • error: sự kiện này được kích hoạt khi xảy ra lỗi.sự kiện này được kích hoạt khi xảy ra lỗi.
  • finish: sự kiện này được kích hoạt khi hoàn thànhsự kiện này được kích hoạt khi hoàn thành

Obejct Mode trong Stream NodeJS

Tất cả các streams được tạo bởi Nodejs API được hoạt động trên các đối tượng kiểu chuỗi và Buffer (hoặc Uint8Array). Tuy nhiên stream đôi lúc làm việc với các kiểu giá trị khác nhau của Javascript (ngoại trừ giá trị null).kiểu chuỗi và Buffer (hoặc Uint8Array). Tuy nhiên stream đôi lúc làm việc với các kiểu giá trị khác nhau của Javascript (ngoại trừ giá trị null).

Bởi vậy chế độ object mode được thêm vào, để sử dụng bạn cần phải chuyển sang chế độ object khi bắt đầu khởi tạo streams. Việc chuyển các streams đã được khởi tạo sang object mode là điểu không an toàn với dữ liệu.

Thao tác với Stream trong NodeJS

Streams là một chức năng rất mạnh trong Nodejs, tưởng tượng khi bạn làm việc với dữ liệu lớn trực tiếp bạn cần phải có một vùng nhớ đủ lớn để lưu trữ nó. Giả sử chúng ta có một file text 10GB mà trong khi đó server của bạn chỉ có 1GB Ram, để đọc file này ngay thì server sẽ không thể thực hiên được vì thiếu bộ nhớ. Streams cho phép chúng ta đọc các dữ liệu lớn bằng cách chia nhỏ dữ liệu ra và đọc giá trị theo từng phần.là một chức năng rất mạnh trong Nodejs, tưởng tượng khi bạn làm việc với dữ liệu lớn trực tiếp bạn cần phải có một vùng nhớ đủ lớn để lưu trữ nó. Giả sử chúng ta có một file text 10GB mà trong khi đó server của bạn chỉ có 1GB Ram, để đọc file này ngay thì server sẽ không thể thực hiên được vì thiếu bộ nhớ. Streams cho phép chúng ta đọc các dữ liệu lớn bằng cách chia nhỏ dữ liệu ra và đọc giá trị theo từng phần.

Đọc dữ liệu với Streams

Chúng ta có file dữ liệu dạng text ở file 

var fs = require('fs');
 
var readStream = fs.createReadStream('test.txt');
var writeStream = fs.createWriteStream('write_file.txt');

readStream.setEncoding('utf8');
readStream.pipe(writeStream);
0 như sau :

hocweb.vn

Tạo file 

var fs = require('fs');
 
var readStream = fs.createReadStream('test.txt');
var writeStream = fs.createWriteStream('write_file.txt');

readStream.setEncoding('utf8');
readStream.pipe(writeStream);
1và khai báo sử dụng module fs,và sử dụng phương thức createReadStream() tham số là đường dẫn file bạn muốn đọc ở đây là 
var fs = require('fs');
 
var readStream = fs.createReadStream('test.txt');
var writeStream = fs.createWriteStream('write_file.txt');

readStream.setEncoding('utf8');
readStream.pipe(writeStream);
0module fs,và sử dụng phương thức createReadStream() tham số là đường dẫn file bạn muốn đọc ở đây là 
var fs = require('fs');
 
var readStream = fs.createReadStream('test.txt');
var writeStream = fs.createWriteStream('write_file.txt');

readStream.setEncoding('utf8');
readStream.pipe(writeStream);
0

const fs = require("fs");
let data = '';
// Đọc file bằng streams bằng phương thức createReadStream
const readerStream = fs.createReadStream('input.txt');
// Kiểu mã hóa dùng là UTF8
readerStream.setEncoding('UTF8');
// Sự kiện khi đọc data
readerStream.on('data', function(chunk) {
   data += chunk;
});
//Khi kết thúc đọc data và in ra nội dung đã đọc
readerStream.on('end',function(){
   console.log(data)
});
//Khi xảy ra lỗi in ra lỗi
readerStream.on('error', function(err){
   console.log(err.stack);
});

Mở terminal và chạy dòng lệnh để xem kết quả:

node readStream.js

Ghi dữ liệu với Streams

Với NodeJS, để ghi một file từ streams chúng ta sử dụng phương thức createWriteStream() trong module fs. Tạo file 

var fs = require('fs');
 
var readStream = fs.createReadStream('test.txt');
var writeStream = fs.createWriteStream('write_file.txt');

readStream.setEncoding('utf8');
readStream.pipe(writeStream);
3streams chúng ta sử dụng phương thức createWriteStream() trong module fs. Tạo file 
var fs = require('fs');
 
var readStream = fs.createReadStream('test.txt');
var writeStream = fs.createWriteStream('write_file.txt');

readStream.setEncoding('utf8');
readStream.pipe(writeStream);
3

const fs = require("fs");
let data = 'hocweb.vn';
//Sử dụng phương thức createWriteStream
const writerStream = fs.createWriteStream('output.txt');
// Ghi dữ liệu vào file
writerStream.write(data);
// Đánh dấu đây là cuối file
writerStream.end();
// Bắt sự kiện finish của Streams
writerStream.on('finish', function() {
    console.log("Write done.");
});
// Bắt sự kiện error khi xảy ra lỗi
writerStream.on('error', function(err){
   console.log(err.stack);
});

Mở terminal và chay dòng lệnh :

node writeStreams.js

Lúc này chúng ta sẽ nhận được 1 file mới có có tên output.txt có nội dung

hocweb.vn

Kĩ thuật Piping Stream trong Node.js

Trong 2 phần trước chúng ta đã tìm hiểu về cách đọc và ghi file sử dụng Streams. Trong Streams ta còn có một khái niệm khác nữa đó là Piping (đường ống) cho phép chúng ta lấy dữ liệu đầu ra từ một stream làm đầu vào trong streams khác. Nó hoạt động như một đường ống giúp chuyển dữ liệu giữa các streams với nhau.Streams. Trong Streams ta còn có một khái niệm khác nữa đó là Piping (đường ống) cho phép chúng ta lấy dữ liệu đầu ra từ một stream làm đầu vào trong streams khác. Nó hoạt động như một đường ống giúp chuyển dữ liệu giữa các streams với nhau.

Trong ví dụ này chúng ta lấy dữ liệu của file input.txt làm dữ liệu đầu vào cho file output.txt bằng cách tạo 2 streams và nối với nhau bằng phương thức pipe :pipe :

var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
0

Tiến hành chay đoạn code trên ta sẽ thất kết quả ở file output.txt

hocweb.vn

Kỹ thuật Piping Chaining trong Node.js

Piping Chaining là kĩ thuật để kết nối đầu ra của các streams lại với nhau, nối đầu ra của streams này với streams khác tạo thành một chuỗi bao gồm nhiều các streams. Nó được sử dụng với cách hoạt động của piping. Chúng ta dùng kỹ thuật này để lấy đầu ra của một file, nén nó lại sau đó tiến hành ghi file nén đó ra trong NodeJS là kĩ thuật để kết nối đầu ra của các streams lại với nhau, nối đầu ra của streams này với streams khác tạo thành một chuỗi bao gồm nhiều các streams. Nó được sử dụng với cách hoạt động của piping. Chúng ta dùng kỹ thuật này để lấy đầu ra của một file, nén nó lại sau đó tiến hành ghi file nén đó ra trong NodeJS

var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
2

Khi chạy chương trình trên, chương trình sẽ lấy đầu ra của file input.txt để nén file sau đó sẽ tạo ra một file nén mới có tên output.txt.gz. Đây là một kỹ thuật được sử dụng khá nhiều.

Một số ví dụ với Streams trong NodeJS

Nếu như phần trên chúng ta tìm hiểu về các thao tác với streams thì trong phần này mình sẽ đưa ra vài ví dụ để chứng minh sức mạnh của Streams trong việc xử lý dữ liệu.Streams trong việc xử lý dữ liệu.

Ghi file dữ liệu lớn sử dụng Streams

Đối với việc ghi một file lớn một cách thông thường bạn cần phải sử dụng rất nhiều bộ nhớ để xử lý việc ghi file. Nhưng đối với streams việc ghi file dữ liệu lớn không tốn quá nhiều bộ nhớ.

var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
3

Khi bạn ghi file bằng streams nó sẽ ghi vào file theo từng mảnh (chunk).

Đọc file dữ liệu lớn sử dụng Streams

Chúng ta có một file vài GB, nếu bạn đọc thông thường thì server sẽ quá tải. Cách thức hoạt động của streams trong đọc file lớn là sẽ chia đọc theo từng phần. Khái niệm 

var fs = require('fs');
 
var readStream = fs.createReadStream('test.txt');
var writeStream = fs.createWriteStream('write_file.txt');

readStream.setEncoding('utf8');
readStream.pipe(writeStream);
4 là kích cỡ của dữ liệu của mỗi chunk khi trong streams.

Giả sử dung lượng của file

var fs = require('fs');
 
var readStream = fs.createReadStream('test.txt');
var writeStream = fs.createWriteStream('write_file.txt');

readStream.setEncoding('utf8');
readStream.pipe(writeStream);
5 là 40GB, nếu ta đọc file theo cách thông thường mất khá nhiều vùng nhớ :

var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
4

Kết quả::

Hướng dẫn createwritestream nodejs - createwritestream nodejs

còn đây là đọc file sử dụng streams :streams :

var fs = require('fs');

var read_string = fs.readFile('big_file.txt', 'utf8', function (err, data) {
    if (err) {
        return console.error(err);
    }
    fs.writeFileSync('big_file2.txt', read_string);
5Kết luận
Hướng dẫn createwritestream nodejs - createwritestream nodejs

Kết luận

Qua bài viết, bạn đã hiểu về Stream và cách sử dụng hiệu quả. Hãy áp dụng vào project, app của bản thân để tận dụng tối đa.

Tìm hiểu thêm về NodeJS : Tối ưu tốc độ ứng dụng NodeJS khi lập trình

Hướng dẫn createwritestream nodejs - createwritestream nodejs

Bài viết này được sưu tầm và tổng hợp từ nhiều nguồn trên Internet.

Nếu có gì không hiểu thì inbox messenger bên dưới mình hỗ trợ thêm nhé.