node.js: đọc tệp văn bản thành một mảng. (Mỗi dòng một mục trong mảng.)


163

Tôi muốn đọc một tệp rất, rất lớn thành một mảng JavaScript trong tệp node.js.

Vì vậy, nếu tập tin là như thế này:

first line
two 
three
...
...

Tôi sẽ có mảng:

['first line','two','three', ... , ... ] 

Các chức năng sẽ trông như thế này:

var array = load(filename); 

Do đó, ý tưởng tải tất cả dưới dạng một chuỗi và sau đó tách nó không được chấp nhận.


Câu hỏi này cần một số chỉnh sửa và dọn dẹp nghiêm trọng. Nó nói đọc một tệp văn bản thành một mảng , nhưng khi bạn đọc tất cả các câu trả lời và nhận xét, nó thực sự có nghĩa là đọc một tệp văn bản một dòng tại một thời điểm . Đối với câu hỏi đó @zswang có câu trả lời tốt nhất cho đến nay.
Jess

yup chỉ cần đọc tệp đó và đẩy từng dòng vào một mảng: stackoverflow.com/a/34033928/1536309
Blair Anderson

Câu trả lời:


89

Nếu bạn có thể điều chỉnh dữ liệu cuối cùng thành một mảng thì bạn cũng không thể điều chỉnh nó trong một chuỗi và phân tách nó, như đã được đề xuất? Trong mọi trường hợp nếu bạn muốn xử lý tệp một dòng tại một thời điểm, bạn cũng có thể thử một cái gì đó như thế này:

var fs = require('fs');

function readLines(input, func) {
  var remaining = '';

  input.on('data', function(data) {
    remaining += data;
    var index = remaining.indexOf('\n');
    while (index > -1) {
      var line = remaining.substring(0, index);
      remaining = remaining.substring(index + 1);
      func(line);
      index = remaining.indexOf('\n');
    }
  });

  input.on('end', function() {
    if (remaining.length > 0) {
      func(remaining);
    }
  });
}

function func(data) {
  console.log('Line: ' + data);
}

var input = fs.createReadStream('lines.txt');
readLines(input, func);

EDIT: (để phản hồi nhận xét của phopkins ) Tôi nghĩ (ít nhất là trong các phiên bản mới hơn) chuỗi con không sao chép dữ liệu mà tạo ra một đối tượng DiledString đặc biệt (từ cái nhìn nhanh vào mã nguồn v8). Trong mọi trường hợp, đây là một sửa đổi để tránh chuỗi con được đề cập (được thử nghiệm trên một tệp có giá trị vài megabyte "Tất cả công việc và không chơi khiến Jack trở thành một cậu bé ngớ ngẩn"):

function readLines(input, func) {
  var remaining = '';

  input.on('data', function(data) {
    remaining += data;
    var index = remaining.indexOf('\n');
    var last  = 0;
    while (index > -1) {
      var line = remaining.substring(last, index);
      last = index + 1;
      func(line);
      index = remaining.indexOf('\n', last);
    }

    remaining = remaining.substring(last);
  });

  input.on('end', function() {
    if (remaining.length > 0) {
      func(remaining);
    }
  });
}

Cảm ơn. để trả lời câu hỏi của bạn: không, chuỗi sẽ quá lớn.
chacko

7
Tôi đã thử điều này trên các tệp khoảng 2 MB hoặc lâu hơn và nó rất chậm, chậm hơn nhiều so với việc đọc trong các tệp một cách đồng bộ thành một chuỗi. Tôi nghĩ vấn đề là dòng còn lại = còn lại. "Dữ liệu" của Node có thể cung cấp cho bạn rất nhiều lần và thực hiện bản sao đó cho mỗi dòng nhanh chóng trở thành O (n ^ 2).
Fiona Hopkins

Câu trả lời của @ Finbar tốt hơn nhiều
r-

442

Đồng bộ:

var fs = require('fs');
var array = fs.readFileSync('file.txt').toString().split("\n");
for(i in array) {
    console.log(array[i]);
}

Không đồng bộ:

var fs = require('fs');
fs.readFile('file.txt', function(err, data) {
    if(err) throw err;
    var array = data.toString().split("\n");
    for(i in array) {
        console.log(array[i]);
    }
});

11
cảm ơn. Thật không may, tôi đã phải chỉnh sửa câu hỏi của tôi. Tôi có nghĩa là làm thế nào để đọc một tập tin lớn. Đọc tất cả trong một chuỗi không được chấp nhận.
chacko

1
Đúng thứ tôi cần. Đơn giản và nhanh chóng.
Hcabnettek

16
Tôi thấy làm điều này trên một tệp được tạo bởi Windows, tôi đã phải tách \ r \ n nhưng điều đó đã phá vỡ máy Mac; Vì vậy, một mạnh mẽ hơn; _array = string.replace (/ \ r \ n / g, '\ n'). split ('\ n'); làm việc cho cả hai
Will Hancock

6
+1 Có một số vấn đề trong Stackoverflow. Bây giờ, tôi thường tìm thấy câu trả lời được bình chọn cao sau khi cuộn xuống quá xa. Đây cũng là một ví dụ về điều này. Nó có quyền biểu quyết cao nhất nhưng được đặt ở cuối trang, rất cuối cùng. Tôi nghĩ Stackoverflow cần cải thiện thuật toán đặt hàng của họ.
shashwat

1
@shashwat Người đặt câu hỏi sẽ quyết định câu trả lời đúng. Trong trường hợp này, họ cần một giải pháp phát trực tuyến cho các tệp lớn và đặt toàn bộ tệp vào một chuỗi là không thể chấp nhận được. Không có gì sai với SO, thực sự.
hợp pháp hóa

73

Sử dụng Node.js mô-đun readline .

var fs = require('fs');
var readline = require('readline');

var filename = process.argv[2];
readline.createInterface({
    input: fs.createReadStream(filename),
    terminal: false
}).on('line', function(line) {
   console.log('Line: ' + line);
});

1
Đáng buồn là có một vấn đề với giải pháp này: Bạn không nhận được dòng cuối cùng nếu tập tin không có \ncuối! Xem: stackoverflow.com/questions/18450197/ Mạnh
Yves M.

8
Nút đã khắc phục sự cố đó với \ n stackoverflow.com/a/32599033/3763850
Gemtastic

14

js:

var array = fs.readFileSync('file.txt', 'utf8').split('\n');

ts:

var array = fs.readFileSync('file.txt', 'utf8').toString().split('\n');

1
Để ngăn chặn những điều trên TypeError: fs.readFileSync(...).split is not a function, bạn nên sử dụng .toString () như thế này:var array = fs.readFileSync('file.txt', 'utf8').toString().split('\n');
Qua285

11

sử dụng readline ( tài liệu ). đây là một ví dụ đọc tệp css, phân tích cú pháp cho các biểu tượng và viết chúng vào json

var results = [];
  var rl = require('readline').createInterface({
    input: require('fs').createReadStream('./assets/stylesheets/_icons.scss')
  });


  // for every new line, if it matches the regex, add it to an array
  // this is ugly regex :)
  rl.on('line', function (line) {
    var re = /\.icon-icon.*:/;
    var match;
    if ((match = re.exec(line)) !== null) {
      results.push(match[0].replace(".",'').replace(":",''));
    }
  });


  // readline emits a close event when the file is read.
  rl.on('close', function(){
    var outputFilename = './icons.json';
    fs.writeFile(outputFilename, JSON.stringify(results, null, 2), function(err) {
        if(err) {
          console.log(err);
        } else {
          console.log("JSON saved to " + outputFilename);
        }
    });
  });

6

file.linesvới gói JFile

Giả

var JFile=require('jfile');

var myF=new JFile("./data.txt");
myF.lines // ["first line","second line"] ....

Đừng quên trước:

npm install jfile --save

5

Với BufferedReader , nhưng chức năng sẽ không đồng bộ:

var load = function (file, cb){
    var lines = [];
    new BufferedReader (file, { encoding: "utf8" })
        .on ("error", function (error){
            cb (error, null);
        })
        .on ("line", function (line){
            lines.push (line);
        })
        .on ("end", function (){
            cb (null, lines);
        })
        .read ();
};

load ("file", function (error, lines){
    if (error) return console.log (error);
    console.log (lines);
});

4

tôi chỉ muốn thêm câu trả lời tuyệt vời @finbarr, một chút sửa chữa trong ví dụ không đồng bộ:

Không đồng bộ:

var fs = require('fs');
fs.readFile('file.txt', function(err, data) {
    if(err) throw err;
    var array = data.toString().split("\n");
    for(i in array) {
        console.log(array[i]);
    }
    done();
});

@MadPhysicist, xong () là những gì phát hành async. gọi.


3

Đây là một biến thể về câu trả lời ở trên của @mtomis.

Nó tạo ra một dòng các dòng. Nó phát ra các sự kiện 'dữ liệu' và 'kết thúc', cho phép bạn xử lý kết thúc luồng.

var events = require('events');

var LineStream = function (input) {
    var remaining = '';

    input.on('data', function (data) {
        remaining += data;
        var index = remaining.indexOf('\n');
        var last = 0;
        while (index > -1) {
            var line = remaining.substring(last, index);
            last = index + 1;
            this.emit('data', line);
            index = remaining.indexOf('\n', last);
        }
        remaining = remaining.substring(last);
    }.bind(this));

    input.on('end', function() {
        if (remaining.length > 0) {
            this.emit('data', remaining);
        }
        this.emit('end');
    }.bind(this));
}

LineStream.prototype = new events.EventEmitter;

Sử dụng nó như một trình bao bọc:

var lineInput = new LineStream(input);

lineInput.on('data', function (line) {
    // handle line
});

lineInput.on('end', function() {
    // wrap it up
});

1
Bạn sẽ kết thúc với việc có các sự kiện được chia sẻ giữa các trường hợp. var EventEmitter = require('events').EventEmitter; var util = require('util'); function GoodEmitter() { EventEmitter.call(this); } util.inherits(GoodEmitter, EventEmitter);
CTAPbIu_MABP

Những trường hợp bạn đang nói về chính xác?
oferei

1
hãy thử tạo var li1 = new LineStream(input1), li2 = new LineStream(input2);sau đó đếm số lần 'kết thúc' được bắn cho mỗi người
CTAPbIu_MABP

thử nó. "Kết thúc" đã bị sa thải một lần cho mỗi trường hợp. var fs = require('fs'); var input1 = fs.createReadStream('text.txt'); var ls1 = new LineStream(input1); ls1.on('data', function (line) { console.log('1:line=' + line); }); ls1.on('end', function (line) { console.log('1:fin'); }); var input2 = fs.createReadStream('text.txt'); var ls2 = new LineStream(input2); ls2.on('data', function (line) { console.log('2:line=' + line); }); ls2.on('end', function (line) { console.log('2:fin'); }); đầu ra: mỗi dòng trong tệp văn bản được kích hoạt một lần cho mỗi phiên bản. vậy là 'kết thúc'.
oferei

2

Tôi đã có cùng một vấn đề và tôi đã giải quyết nó với từng dòng mô-đun

https://www.npmjs.com/package/line-by-line

Ít nhất đối với tôi hoạt động như một bùa mê, cả ở chế độ đồng bộ và không đồng bộ.

Ngoài ra, có thể giải quyết vấn đề với các dòng kết thúc không kết thúc \ n với tùy chọn:

{ encoding: 'utf8', skipEmptyLines: false }

Xử lý đồng bộ các dòng:

var LineByLineReader = require('line-by-line'),
    lr = new LineByLineReader('big_file.txt');

lr.on('error', function (err) {
    // 'err' contains error object
});

lr.on('line', function (line) {
    // 'line' contains the current line without the trailing newline character.
});

lr.on('end', function () {
    // All lines are read, file is closed now.
}); 

2

Sử dụng Node.js v8 trở lên có một tính năng mới chuyển đổi chức năng bình thường thành chức năng không đồng bộ.

tận dụng

Đó là một tính năng tuyệt vời. Dưới đây là ví dụ về phân tích 10000 số từ tệp txt thành một mảng, đếm các nghịch đảo bằng cách sử dụng sắp xếp hợp nhất trên các số.

// read from txt file
const util = require('util');
const fs = require('fs')
fs.readFileAsync = util.promisify(fs.readFile);
let result = []

const parseTxt = async (csvFile) => {
  let fields, obj
  const data = await fs.readFileAsync(csvFile)
  const str = data.toString()
  const lines = str.split('\r\n')
  // const lines = str
  console.log("lines", lines)
  // console.log("str", str)

  lines.map(line => {
    if(!line) {return null}
    result.push(Number(line))
  })
  console.log("result",result)
  return result
}
parseTxt('./count-inversion.txt').then(() => {
  console.log(mergeSort({arr: result, count: 0}))
})

1

Để đọc một tệp lớn thành mảng, bạn có thể đọc từng dòng hoặc từng đoạn một.

từng dòng tham khảo câu trả lời của tôi ở đây

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

var lines = [];

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

chunk by chunk tham khảo bài viết này

var offset = 0;
var chunkSize = 2048;
var chunkBuffer = new Buffer(chunkSize);
var fp = fs.openSync('filepath', 'r');
var bytesRead = 0;
while(bytesRead = fs.readSync(fp, chunkBuffer, 0, chunkSize, offset)) {
    offset += bytesRead;
    var str = chunkBuffer.slice(0, bytesRead).toString();
    var arr = str.split('\n');

    if(bytesRead = chunkSize) {
        // the last item of the arr may be not a full line, leave it to the next chunk
        offset -= arr.pop().length;
    }
    lines.push(arr);
}
console.log(lines);
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.