Đọc tệp văn bản bằng Node.js?


124

Tôi cần chuyển vào một tệp văn bản trong thiết bị đầu cuối và sau đó đọc dữ liệu từ tệp đó, tôi có thể thực hiện việc này như thế nào?

node server.js file.txt

Làm cách nào để đi qua đường dẫn từ nhà ga, làm cách nào để đọc ở phía bên kia?


Nếu bạn thấy mình thêm nhiều tùy chọn hơn trên dòng lệnh, bạn có thể sử dụng Optimist .
Jess

stackoverflow.com/questions/6156501/… hiển thị một cách khác để đọc tệp văn bản
Marc Durdin

Câu trả lời:


172

Bạn sẽ muốn sử dụng process.argvmảng để truy cập các đối số dòng lệnh để lấy tên tệp và mô-đun FileSystem (fs) để đọc tệp. Ví dụ:

// Make sure we got a filename on the command line.
if (process.argv.length < 3) {
  console.log('Usage: node ' + process.argv[1] + ' FILENAME');
  process.exit(1);
}
// Read the file and print its contents.
var fs = require('fs')
  , filename = process.argv[2];
fs.readFile(filename, 'utf8', function(err, data) {
  if (err) throw err;
  console.log('OK: ' + filename);
  console.log(data)
});

Để chia nhỏ điều đó một chút cho bạn, process.argvthường sẽ có độ dài hai, mục thứ 0 là trình thông dịch "nút" và mục đầu tiên là tập lệnh mà nút hiện đang chạy, các mục sau đó được chuyển trên dòng lệnh. Khi bạn đã lấy tên tệp từ argv thì bạn có thể sử dụng các chức năng của hệ thống tệp để đọc tệp và làm bất cứ điều gì bạn muốn với nội dung của nó. Cách sử dụng mẫu sẽ như thế này:

$ node ./cat.js file.txt
OK: file.txt
This is file.txt!

[Chỉnh sửa] Như @wtfcoder đã đề cập, sử dụng fs.readFile()phương thức "" có thể không phải là ý tưởng tốt nhất vì nó sẽ đệm toàn bộ nội dung của tệp trước khi chuyển nó cho hàm gọi lại. Bộ đệm này có thể sử dụng nhiều bộ nhớ nhưng quan trọng hơn, nó không tận dụng được một trong những tính năng cốt lõi của node.js - I / O không đồng bộ, có sự kiện.

Cách "nút" để xử lý một tệp lớn (hoặc bất kỳ tệp nào, thực sự) sẽ là sử dụng fs.read()và xử lý từng đoạn có sẵn vì nó có sẵn từ hệ điều hành. Tuy nhiên, việc đọc tệp như vậy đòi hỏi bạn phải tự mình (có thể) phân tích / xử lý tệp tăng dần và một số bộ đệm có thể không tránh khỏi.


Tuyệt vời, cảm ơn rất nhiều, rất hữu ích. Làm cách nào để chia dữ liệu này theo từng dòng?
ưa thích

10
@fancy: thử xem var lines = data.split(/\r?\n/);, mảng "lines" sẽ có mỗi dòng.
maerics

1
Đây không phải là một ý tưởng hay nếu tệp văn bản lớn, vì tất cả nó sẽ được đọc vào bộ nhớ, nếu bạn xử lý tệp CSV 1000mb, hãy nhìn vào fs.createFilestream, bạn sẽ cần phải cẩn thận với việc phân chia dòng mặc dù dữ liệu bị chia nhỏ. sẽ không (trong hầu hết các trường hợp) rơi trên chỉ giới đường (một số người đã đưa ra giải pháp - google)
Matt Freeman

1
@wtfcoder: vâng, điểm rất tốt. Mục đích của tôi là chỉ để chứng minh trường hợp đơn giản là đọc một tệp có tên trên dòng lệnh; rõ ràng là có nhiều điều tinh tế (đặc biệt là hiệu suất) nằm ngoài phạm vi của câu hỏi này.
maerics

Tôi đã đăng một giải pháp cho một câu hỏi tương tự để phân tích cú pháp một tệp rất lớn, sử dụng một luồng, đồng bộ. xem: stackoverflow.com/questions/16010915/…
Gerard

35

Ký hiệu fs với nút.

var fs = require('fs');

try {  
    var data = fs.readFileSync('file.txt', 'utf8');
    console.log(data.toString());    
} catch(e) {
    console.log('Error:', e.stack);
}

Lưu ý rằng đây là phiên bản đồng bộ .
Rich Werden

@RichWerden bạn hiểu "đồng bộ" trong ngữ cảnh này là gì?
Json

1
Trong Node khi một thứ gì đó "đồng bộ", nó sẽ dừng / chặn hệ thống làm bất cứ điều gì khác. Giả sử bạn có một máy chủ web nút - nếu bất kỳ yêu cầu nào khác đến trong khi điều trên đang xảy ra, máy chủ sẽ không / không thể phản hồi vì nó đang bận đọc tệp.
Rich Werden

27

IMHO, fs.readFile()nên tránh vì nó tải TẤT CẢ tệp trong bộ nhớ và nó sẽ không gọi lại cho đến khi tất cả tệp đã được đọc.

Cách dễ nhất để đọc tệp văn bản là đọc từng dòng một. Tôi đề xuất một BufferedReader :

new BufferedReader ("file", { encoding: "utf8" })
    .on ("error", function (error){
        console.log ("error: " + error);
    })
    .on ("line", function (line){
        console.log ("line: " + line);
    })
    .on ("end", function (){
        console.log ("EOF");
    })
    .read ();

Đối với các cấu trúc dữ liệu phức tạp như tệp .properties hoặc json, bạn cần sử dụng trình phân tích cú pháp (bên trong nó cũng nên sử dụng trình đọc đệm).


7
Cảm ơn vì đã chỉ ra kỹ thuật này. Bạn nói đúng rằng đây có thể là cách tốt nhất, nhưng tôi chỉ nghĩ rằng nó hơi khó hiểu trong bối cảnh của câu hỏi này, mà tôi nghĩ đang hỏi về một trường hợp sử dụng không bắt buộc. Như đã chỉ ra ở trên, nếu nó chỉ là một tệp nhỏ được chuyển đến một công cụ dòng lệnh, không có lý do gì để không sử dụng fs.readFile()hoặc fs.readFileSync(). Nó phải là một tệp lớn để gây ra sự chờ đợi đáng chú ý. Một tệp cấu hình JSON như package.json có thể dưới 1 kb, vì vậy bạn có thể chỉ cần fs.readFile()JSON.parse()nó.
John Starr Dewar

1
BufferedReader có thể đã thay đổi chữ ký của nó. Tôi đã phải thay thế BufferedReader bằng BufferedReader, DataReader, trong đó BufferedReader là mô-đun. Xem github.com/Gagle/Node-BufferedReader
bnieland

13
Tôi thấy rằng BufferedReader hiện không được dùng nữa.
Marc Rochkind

6

Bạn có thể sử dụng readstream và pipe để đọc từng dòng của tệp mà không cần đọc tất cả tệp vào bộ nhớ một lần.

var fs = require('fs'),
    es = require('event-stream'),
    os = require('os');

var s = fs.createReadStream(path)
    .pipe(es.split())
    .pipe(es.mapSync(function(line) {
        //pause the readstream
        s.pause();
        console.log("line:", line);
        s.resume();
    })
    .on('error', function(err) {
        console.log('Error:', err);
    })
    .on('end', function() {
        console.log('Finish reading.');
    })
);

5

Tôi đang đăng một ví dụ hoàn chỉnh mà cuối cùng tôi đã làm việc. Ở đây tôi đang đọc trong một tệp rooms/rooms.txttừ một tập lệnhrooms/rooms.js

var fs = require('fs');
var path = require('path');
var readStream = fs.createReadStream(path.join(__dirname, '../rooms') + '/rooms.txt', 'utf8');
let data = ''
readStream.on('data', function(chunk) {
    data += chunk;
}).on('end', function() {
    console.log(data);
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.