Nút. js kể từ phiên bản 7 cung cấp mô-đun
node readfilesync.js
8 để thực hiện chính xác điều này. nhận đầu vào từ một luồng có thể đọc được, chẳng hạn như luồng node readfilesync.js
9, trong quá trình thực thi Nút. chương trình js là đầu vào đầu cuối, mỗi lần một dòngJScopy
Đoạn mã này hỏi tên người dùng và khi văn bản được nhập và người dùng nhấn enter, chúng tôi sẽ gửi lời chào
Phương thức
node readfilesync.js
0 hiển thị tham số đầu tiên [một câu hỏi] và đợi người dùng nhập liệu. Nó gọi chức năng gọi lại sau khi nhấn enterTrong chức năng gọi lại này, chúng tôi đóng giao diện đường đọc
node readfilesync.js
8 cung cấp một số phương pháp khác, vui lòng kiểm tra chúng trên tài liệu gói được liên kết ở trênNếu bạn cần yêu cầu mật khẩu, tốt nhất không nên lặp lại mật khẩu mà thay vào đó hãy hiển thị ký hiệu
node readfilesync.js
2Cách đơn giản nhất là sử dụng gói
node readfilesync.js
3 rất giống nhau về API và xử lý việc này ngay lập tứcMột giải pháp đầy đủ và trừu tượng hơn được cung cấp bởi Inquirer. gói js
Bạn có thể cài đặt nó bằng cách sử dụng
node readfilesync.js
4, sau đó bạn có thể sao chép đoạn mã trên như thế nàyJScopy
người hỏi. js cho phép bạn làm nhiều việc như hỏi nhiều lựa chọn, có các nút radio, xác nhận, v.v.
Thật đáng để biết tất cả các lựa chọn thay thế, đặc biệt là những lựa chọn tích hợp do Node cung cấp. js, nhưng nếu bạn định đưa đầu vào CLI lên cấp độ tiếp theo, Inquirer. js là một lựa chọn tối ưu
Có nhiều cách để đọc từng dòng tệp với Node. js. trong nút. các tệp js có thể được đọc theo cách đồng bộ hóa hoặc theo cách không đồng bộ. Với đường dẫn không đồng bộ, có thể đọc các tệp lớn mà không cần tải tất cả nội dung của tệp vào bộ nhớ
Đọc toàn bộ tệp cùng một lúc sẽ làm cho bộ nhớ quá trình trở nên nặng nề. Với khả năng tải và đọc từng dòng tệp, nó cho phép chúng tôi dừng quá trình ở bất kỳ bước nào theo nhu cầu. Trong bài đăng này, chúng ta sẽ xem xét 3 cách để đọc từng dòng tệp bằng cách sử dụng Node. js với so sánh sử dụng bộ nhớ
Mục lục
điều kiện tiên quyết
Trước khi chuyển sang mã, bên dưới là một số điều kiện tiên quyết cần tuân theo cùng với các ví dụ mã được cung cấp
- Có nút. js 14+ [tốt nhất là LTS Node 18 mới nhất] chạy trên máy/môi trường thử nghiệm của bạn là bắt buộc. Bạn thậm chí có thể sử dụng Nút. js trên docker cho nó
- Kiến thức về cách cài đặt các mô-đun NPM sẽ là cần thiết
- Mọi hiểu biết trước về các luồng và cách chúng hoạt động sẽ hữu ích
- Mọi kiến thức về kiến trúc dựa trên sự kiện của Node sẽ rất hữu ích nếu bạn có
Tôi đang chạy mã trên máy Mac bằng Node. js 14. Trong phần sau, chúng ta sẽ xem xét tệp mà chúng ta sẽ sử dụng để đọc từng dòng với Node. js. Các ví dụ mã có sẵn trong kho lưu trữ GitHub công khai để thuận tiện cho bạn
tập tin thử nghiệm
Đối với tất cả các đường chạy bên dưới, chúng tôi sẽ sử dụng tệp kết xuất SQL 90 MB mà tôi đã lấy từ kho lưu trữ bản sao BroadBandNow này. Cùng một tệp được sử dụng cho từng phương pháp đọc từng dòng tệp trong Nút. js để giữ cho bài kiểm tra nhất quán giữa các phương thức. Chúng tôi cũng sẽ xem xét mức tiêu thụ bộ nhớ và thời gian để đọc tệp 90 MB có 798148 dòng văn bản. Đây sẽ là một thử nghiệm tốt để xem cách những cách này hoạt động đối với một tệp tương đối lớn
Đọc đồng bộ tập tin
Chúng tôi có thể đọc tệp theo cách đồng bộ, nghĩa là tải toàn bộ tệp 90 MB vào bộ nhớ và lặp qua nó. Tuy nhiên, vì chúng tôi sẽ tải toàn bộ tệp trước khi đọc bất kỳ dòng nào từ tệp nên mức tiêu thụ bộ nhớ chắc chắn sẽ hơn 90 MB. Đây là một ví dụ nhanh để đọc từng dòng tệp nhưng theo cách đồng bộ hóa không hiệu quả lắm
const fs = require['fs'];
const allFileContents = fs.readFileSync['broadband.sql', 'utf-8'];
allFileContents.split[/\r?\n/].forEach[line => {
console.log[`Line from file: ${line}`];
}];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
Vì chúng tôi đang sử dụng mô-đun
node readfilesync.js
5 là mô-đun gốc nên không cần cài đặt bất kỳ mô-đun NPM mới nào. Trong đoạn mã trên, chúng tôi đang đọc tệp while một cách đồng bộ, sau đó lặp qua từng dòng một và in nó ra bàn điều khiển bằng một node readfilesync.js
6Sau khi lặp xong, chúng tôi in ra mức sử dụng bộ nhớ gần đúng. Mã này có thể được tìm thấy trong yêu cầu kéo này để bạn tham khảo. Nếu chúng tôi chạy tập lệnh này với tiền tố thời gian như bên dưới
node readfilesync.js
Nó sẽ chạy và kết thúc với đầu ra như sau
Như mong đợi đối với tệp 90 MB, nó chiếm ~225 MB bộ nhớ và mất 7. 85 giây để nó lặp qua 798 nghìn dòng văn bản
Nếu có tệp 1 GB, không nên sử dụng phương pháp này vì nó sẽ hết bộ nhớ khi cố tải toàn bộ tệp vào bộ nhớ
Tiếp theo, chúng ta sẽ xem xét một cách không đồng bộ hiệu quả hơn để đọc từng dòng tệp với
node readfilesync.js
0 và một luồng là một Node gốc khác. mô-đun jsdòng đọc
Readline là một Node gốc. js nên không cần cài đặt mô-đun NPM mới để sử dụng nó. Nó có thể được sử dụng để đọc từng dòng tệp bằng cách đọc từng dòng một từ bất kỳ luồng nào có thể đọc được. Chúng tôi sẽ sử dụng phương thức on với
node readfilesync.js
1 được phát ra khi luồng đầu vào nhận được đầu vào cuối dòng node readfilesync.js
2 hoặc node readfilesync.js
3Dưới đây là ví dụ mã của readline với luồng có thể đọc được
________số 8Hãy hiểu những gì đang xảy ra trong kịch bản trên. Trước tiên, chúng tôi yêu cầu 3 nút gốc. js mô-đun sự kiện, fs và readline. Sau đó, chúng tôi xác định hàm async có tên là
node readfilesync.js
4 để tạo giao diện cho đường đọc trong đó đầu vào là một đường đọc nơi chúng tôi chuyển tệp kiểm tra 90 MB của mình. Theo crlfDelay được đặt thành vô cùng sẽ coi node readfilesync.js
5 theo sau là node readfilesync.js
6 dưới dạng một dòng mớiKhi chúng ta đang tương tác với một luồng có thể đọc được, trên mỗi sự kiện đọc dòng, nó sẽ gọi hàm
node readfilesync.js
7 với sự kiện node readfilesync.js
1. Tại thời điểm đó, chúng tôi ghi lại nội dung của dòng được đọc từ luồng. Sau đó, chúng tôi lắng nghe sự kiện đóng dòng đọc với node readfilesync.js
9 sẽ giải quyết bằng một mảng gồm tất cả các đối số được phát ra cho sự kiện đã cho. Nó sẽ là một mảng trống trong trường hợp nàyCuối cùng, chúng tôi đọc mức sử dụng bộ nhớ và ghi nhật ký. Bạn có thể tham khảo mã trên trong yêu cầu kéo này. Khi chúng tôi chạy tập lệnh này với
5JScopy
Nó mang lại đầu ra sau
Như đã thấy ở trên, mô-đun readline với luồng có thể đọc được chỉ mất 6. Bộ nhớ 33 MB để đọc tệp 90 MB
Vì nó được phát trực tuyến, nhỏ hơn rất nhiều so với 225 MB trong ví dụ đồng bộ hóa trước đó
Nó hoàn thành quá trình trong 7. 365 giây. Tiếp theo, chúng ta sẽ xem xét mô-đun NPM N-readlines để đọc từng dòng tệp
N-readlines
N-readline là một mô-đun NPM sẽ đọc từng dòng tệp mà không đệm toàn bộ tệp trong bộ nhớ. Nó thực hiện điều này mà không cần sử dụng các luồng bằng cách đọc nội dung của tệp bằng cách sử dụng và mô-đun hệ thống tệp gốc. Mặc dù nó hoạt động theo cách đồng bộ nhưng nó không tải toàn bộ tệp vào bộ nhớ
Dưới đây là một ví dụ về cách sử dụng N-readline để đọc từng dòng tệp sau khi cài đặt nó với
const events = require['events'];
const fs = require['fs'];
const readline = require['readline'];
[async function processLineByLine[] {
try {
const rl = readline.createInterface[{
input: fs.createReadStream['broadband.sql'],
crlfDelay: Infinity
}];
rl.on['line', [line] => {
console.log[`Line from file: ${line}`];
}];
await events.once[rl, 'close'];
console.log['Reading file line by line with readline done.'];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
} catch [err] {
console.error[err];
}
}][];
07JScopy
Trong đoạn mã trên, trước tiên, chúng tôi yêu cầu mô-đun
const events = require['events'];
const fs = require['fs'];
const readline = require['readline'];
[async function processLineByLine[] {
try {
const rl = readline.createInterface[{
input: fs.createReadStream['broadband.sql'],
crlfDelay: Infinity
}];
rl.on['line', [line] => {
console.log[`Line from file: ${line}`];
}];
await events.once[rl, 'close'];
console.log['Reading file line by line with readline done.'];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
} catch [err] {
console.error[err];
}
}][];
1 và chúng tôi khởi tạo nó bằng tệp const events = require['events'];
const fs = require['fs'];
const readline = require['readline'];
[async function processLineByLine[] {
try {
const rl = readline.createInterface[{
input: fs.createReadStream['broadband.sql'],
crlfDelay: Infinity
}];
rl.on['line', [line] => {
console.log[`Line from file: ${line}`];
}];
await events.once[rl, 'close'];
console.log['Reading file line by line with readline done.'];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
} catch [err] {
console.error[err];
}
}][];
2 có dung lượng 90 MB. Khác như const events = require['events'];
const fs = require['fs'];
const readline = require['readline'];
[async function processLineByLine[] {
try {
const rl = readline.createInterface[{
input: fs.createReadStream['broadband.sql'],
crlfDelay: Infinity
}];
rl.on['line', [line] => {
console.log[`Line from file: ${line}`];
}];
await events.once[rl, 'close'];
console.log['Reading file line by line with readline done.'];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
} catch [err] {
console.error[err];
}
}][];
3 và const events = require['events'];
const fs = require['fs'];
const readline = require['readline'];
[async function processLineByLine[] {
try {
const rl = readline.createInterface[{
input: fs.createReadStream['broadband.sql'],
crlfDelay: Infinity
}];
rl.on['line', [line] => {
console.log[`Line from file: ${line}`];
}];
await events.once[rl, 'close'];
console.log['Reading file line by line with readline done.'];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
} catch [err] {
console.error[err];
}
}][];
4 có thể được chuyển vào dưới dạng tham số thứ hai trong const events = require['events'];
const fs = require['fs'];
const readline = require['readline'];
[async function processLineByLine[] {
try {
const rl = readline.createInterface[{
input: fs.createReadStream['broadband.sql'],
crlfDelay: Infinity
}];
rl.on['line', [line] => {
console.log[`Line from file: ${line}`];
}];
await events.once[rl, 'close'];
console.log['Reading file line by line with readline done.'];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
} catch [err] {
console.error[err];
}
}][];
5 nhưng chúng tôi sử dụng giá trị mặc địnhDo đó, chúng tôi xác định hai biến
node readfilesync.js
1 và const events = require['events'];
const fs = require['fs'];
const readline = require['readline'];
[async function processLineByLine[] {
try {
const rl = readline.createInterface[{
input: fs.createReadStream['broadband.sql'],
crlfDelay: Infinity
}];
rl.on['line', [line] => {
console.log[`Line from file: ${line}`];
}];
await events.once[rl, 'close'];
console.log['Reading file line by line with readline done.'];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
} catch [err] {
console.error[err];
}
}][];
7. Biến dòng sẽ giữ chuỗi cho mỗi dòng của tệp và const events = require['events'];
const fs = require['fs'];
const readline = require['readline'];
[async function processLineByLine[] {
try {
const rl = readline.createInterface[{
input: fs.createReadStream['broadband.sql'],
crlfDelay: Infinity
}];
rl.on['line', [line] => {
console.log[`Line from file: ${line}`];
}];
await events.once[rl, 'close'];
console.log['Reading file line by line with readline done.'];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
} catch [err] {
console.error[err];
}
}][];
7 sẽ giữ số dòng từ 1 đến số dòng mà tệp cóSau đó, chúng tôi lặp qua các dòng trong khi có các dòng trong tệp có lệnh gọi
const events = require['events'];
const fs = require['fs'];
const readline = require['readline'];
[async function processLineByLine[] {
try {
const rl = readline.createInterface[{
input: fs.createReadStream['broadband.sql'],
crlfDelay: Infinity
}];
rl.on['line', [line] => {
console.log[`Line from file: ${line}`];
}];
await events.once[rl, 'close'];
console.log['Reading file line by line with readline done.'];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
} catch [err] {
console.error[err];
}
}][];
9. Vì nó trả về một bộ đệm nếu một dòng tồn tại, chúng tôi điều khiển ghi nhật ký nó trên CLI sau khi chuyển đổi nó thành chuỗi ASCII. Tiếp theo, chúng tôi tăng số Dòng bên trong vòng lặpCuối cùng, chúng tôi in
50 và giống như các ví dụ trên, chúng tôi cũng in ra mức sử dụng bộ nhớ gần đúng. Mã này cũng có sẵn dưới dạng yêu cầu kéo để bạn tham khảo. Chúng ta có thể thực thi đoạn script trên vớiJScopy
const fs = require['fs'];
const allFileContents = fs.readFileSync['broadband.sql', 'utf-8'];
allFileContents.split[/\r?\n/].forEach[line => {
console.log[`Line from file: ${line}`];
}];
const used = process.memoryUsage[].heapUsed / 1024 / 1024;
console.log[`The script uses approximately ${Math.round[used * 100] / 100} MB`];
8Nó sẽ hiển thị đầu ra sau khi kết thúc quá trình thực thi tập lệnh
Như đã thấy ở trên, nó đã hoàn thành nhiệm vụ trong 8. 9 giây
Để in tất cả 798K dòng của tệp SQL 90 MB, n-readlines chỉ tiêu tốn 4. Bộ nhớ 11 MB thật tuyệt vời
Trong phần sau, chúng ta sẽ xem cách mô-đun NPM đọc dòng có thể được sử dụng để đọc từng dòng tệp với Node. js
đầu đọc dòng
Trình đọc dòng Mô-đun NPM tự định nghĩa là “Trình đọc tệp/luồng không đồng bộ, được đệm, theo từng dòng với sự hỗ trợ cho các dấu tách dòng do người dùng xác định. ” trên trang GitHub của nó. Trong phần của trang, nó cũng đề cập đến hàm
51 đọc từng dòng của tệp đã cho. BiếnJScopy
52 trong hàm gọi lại có thể được sử dụng để xác định xem đã đạt đến dòng cuối cùng của tệp chưaJScopy
Dưới đây là ví dụ hoạt động về cách đọc tệp SQL 90 MB tương đối lớn của chúng tôi bằng trình đọc dòng, chúng tôi đã cài đặt nó với
53 và sau đó tạo tệp sauJScopy
node readfilesync.js
2Đầu tiên, chúng tôi yêu cầu mô-đun trình đọc dòng, sau đó gọi hàm
51 chuyển tên tệp [hoặc đường dẫn tệp] làm tham số đầu tiên. Tham số thứ hai là một hàm gọi lại có dòng và các biến cuối cùng. Sau đó, chúng tôi ghi lại dòng từ tệp có sẵn trong biến dòngJScopy
Tiếp theo, nếu chúng tôi tìm thấy biến cuối cùng là đúng, điều đó cho biết chúng tôi đã đến cuối tệp, chúng tôi ghi lại thông báo
55 và cũng in ra bộ nhớ gần đúng được sử dụng để đọc tệp theo từng dòng. Mã này cũng có sẵn dưới dạng yêu cầu kéo để bạn tham khảoJScopy
Chúng ta có thể chạy mã này bằng cách thực thi
node readfilesync.js
5Nó sẽ kết thúc với một đầu ra giống như sau
Như đã thấy ở trên, kịch bản đã hoàn thành sau 10. 66 giây
So với bộ nhớ 225 MB được sử dụng trong
56, việc đọc tệp 90 MB bằng trình đọc dòng chỉ mất 5. Bộ nhớ 18 MB, ít hơn 45 lầnJScopy
Nếu bạn muốn khởi động lại Node của mình. js trên mỗi thay đổi, hãy dùng thử Nodemon. Tiếp theo, chúng tôi sẽ xem liệu có các tùy chọn khác hay không nhưng chúng tôi chắc chắn đã đề cập đến 3 tùy chọn phổ biến nhất
Sự lựa chọn khác
Có các tùy chọn khác để đọc từng dòng tệp với Node. js. Có một mô-đun NPM rất phổ biến được gọi là readline nhưng do xung đột tên với Node gốc. js, nó đã được đổi tên thành Line By LIne ngay bây giờ. Nó hoạt động rất giống với mô-đun readline gốc
Các tùy chọn khác ít phổ biến hơn nhưng khả dụng là tệp readline và readlines-ng. Cả hai đều là mô-đun NPM nhưng chúng đã được tải xuống khoảng 3 lần mỗi tuần trước
Để xử lý thêm nội dung tệp, sử dụng các hàm mảng JavaScript này sẽ rất hữu ích. Điều này đưa chúng ta đến một so sánh nhanh các tùy chọn có sẵn này
So sánh nhanh
So sánh nhanh bốn mô-đun NPM này trên NPM Trends cho thấy N-readlines là mô-đun được tải xuống nhiều nhất với 56 nghìn lượt tải xuống trong tuần trước. Cái thứ hai là trình đọc dòng với 46 nghìn lượt tải xuống vào tuần trước nhưng hãy nhớ rằng trình đọc dòng được cập nhật lần cuối cách đây 6 năm. Dưới đây là ảnh chụp nhanh các lượt tải xuống trong 1 năm qua
Sẽ tốt hơn nếu chọn những cái phổ biến và cái được cập nhật gần đây nhất là n-readlines cách đây một năm
Số lượt tải xuống cho cả tệp readline và readlines ng là khoảng 3 mỗi tuần so với 46K và 56K cho trình đọc dòng và n-readlines tương ứng
Đưa ra lựa chọn sáng suốt để được hỗ trợ tốt hơn nếu bạn cần. Trong trường hợp bạn muốn đọc nhiều file cùng lúc có thể sử dụng JavaScript Promise. tất cả để hoàn thành công việc
Xét về mức sử dụng bộ nhớ và CPU, tất cả các phương pháp ngoại trừ
57 đầu tiên, tất cả các tùy chọn dựa trên luồng hoặc gọi lại khác đều tiêu thụ dưới 10 MB hoặc bộ nhớ và hoàn thành trước 10 giây với mức sử dụng CPU 70-94%. Đọc đồng bộ hóa tệp tiêu tốn 225 MB bộ nhớ cho tệp 90 MBJScopy
Phần kết luận
Chúng tôi đã xem xét cách đọc từng dòng tệp trong Node. js. Mặc dù có vẻ như là một vấn đề tầm thường nhưng có nhiều cách để thực hiện trong Node. js giống như hầu hết mọi thứ trong JavaScript
Chúng tôi cũng đã phân tích mức sử dụng bộ nhớ và thời gian sử dụng cho từng phương pháp trong số 3 phương pháp
Cuối cùng, chúng tôi đã xem xét so sánh nhanh các tùy chọn này và các tùy chọn khác có sẵn về mức độ phổ biến. Tôi hy vọng nó sẽ giúp bạn đưa ra quyết định sáng suốt để đọc từng dòng tệp với Node. js