Читать файл по одной строке в node.js? - PullRequest
500 голосов
/ 27 мая 2011

Я пытаюсь прочитать большой файл по одной строке за раз.Я нашел вопрос по Quora , который касался предмета, но мне не хватает некоторых связей, чтобы все это сошлось воедино.

 var Lazy=require("lazy");
 new Lazy(process.stdin)
     .lines
     .forEach(
          function(line) { 
              console.log(line.toString()); 
          }
 );
 process.stdin.resume();

Бит, который я хотел бы выяснитьЭто то, как я могу читать по одной строке за раз из файла вместо STDIN, как в этом примере.

Я пытался:

 fs.open('./VeryBigFile.csv', 'r', '0666', Process);

 function Process(err, fd) {
    if (err) throw err;
    // DO lazy read 
 }

, но это не работает.Я знаю, что в крайнем случае я мог бы вернуться к использованию чего-то вроде PHP, но я хотел бы выяснить это.

Не думаю, что другой ответ будет работать, так как файл намного больше, чем у сервера, на котором он запущен, есть память.

Ответы [ 27 ]

1 голос
/ 04 июня 2017

Другое решение - запустить логику через последовательного исполнителя nsynjs .Он читает файл построчно, используя модуль readline узла, и не использует обещания или рекурсию, поэтому не собирается завершать работу с большими файлами.Вот как будет выглядеть код:

var nsynjs = require('nsynjs');
var textFile = require('./wrappers/nodeReadline').textFile; // this file is part of nsynjs

function process(textFile) {

    var fh = new textFile();
    fh.open('path/to/file');
    var s;
    while (typeof(s = fh.readLine(nsynjsCtx).data) != 'undefined')
        console.log(s);
    fh.close();
}

var ctx = nsynjs.run(process,{},textFile,function () {
    console.log('done');
});

Код выше основан на этом примере: https://github.com/amaksr/nsynjs/blob/master/examples/node-readline/index.js

0 голосов
/ 18 января 2019

Я заключаю всю логику ежедневной обработки строки в виде модуля npm: line-kit https://www.npmjs.com/package/line-kit

// example
var count = 0
require('line-kit')(require('fs').createReadStream('/etc/issue'),
                    (line) => { count++; },
                    () => {console.log(`seen ${count} lines`)})
0 голосов
/ 02 мая 2018

Я просмотрел все приведенные выше ответы, все они используют стороннюю библиотеку для ее решения.Это простое решение в Node API.например,

const fs= require('fs')

let stream = fs.createReadStream('<filename>', { autoClose: true })

stream.on('data', chunk => {
    let row = chunk.toString('ascii')
}))
0 голосов
/ 11 сентября 2017

Я использую приведенный ниже код для чтения строк после того, как убедитесь, что это не каталог и его нет в списке файлов. Проверять не нужно.

(function () {
  var fs = require('fs');
  var glob = require('glob-fs')();
  var path = require('path');
  var result = 0;
  var exclude = ['LICENSE',
    path.join('e2e', 'util', 'db-ca', 'someother-file'),
    path.join('src', 'favicon.ico')];
  var files = [];
  files = glob.readdirSync('**');

  var allFiles = [];

  var patternString = [
    'trade',
    'order',
    'market',
    'securities'
  ];

  files.map((file) => {
    try {
      if (!fs.lstatSync(file).isDirectory() && exclude.indexOf(file) === -1) {
        fs.readFileSync(file).toString().split(/\r?\n/).forEach(function(line){
          patternString.map((pattern) => {
            if (line.indexOf(pattern) !== -1) {
              console.log(file + ' contain `' + pattern + '` in in line "' + line +'";');
              result = 1;
            }
          });
        });
      }
    } catch (e) {
      console.log('Error:', e.stack);
    }
  });
  process.exit(result);

})();
0 голосов
/ 30 мая 2017
const fs = require("fs")

fs.readFile('./file', 'utf-8', (err, data) => {
var innerContent;
    console.log("Asynchronous read: " + data.toString());
    const lines = data.toString().split('\n')
    for (let line of lines)
        innerContent += line + '<br>';


});
0 голосов
/ 18 марта 2017

Хотя вам, вероятно, следует использовать модуль readline, как подсказывает главный ответ, readline, по-видимому, ориентирован на интерфейсы командной строки, а не на чтение строки. Это также немного более непрозрачно в отношении буферизации. (Любой, кому нужен читатель, ориентированный на потоковую линию, вероятно, захочет настроить размер буфера). Модуль readline составляет ~ 1000 строк, а со статистикой и тестами - 34.

const EventEmitter = require('events').EventEmitter;
class LineReader extends EventEmitter{
    constructor(f, delim='\n'){
        super();
        this.totalChars = 0;
        this.totalLines = 0;
        this.leftover = '';

        f.on('data', (chunk)=>{
            this.totalChars += chunk.length;
            let lines = chunk.split(delim);
            if (lines.length === 1){
                this.leftover += chunk;
                return;
            }
            lines[0] = this.leftover + lines[0];
            this.leftover = lines[lines.length-1];
            if (this.leftover) lines.pop();
            this.totalLines += lines.length;
            for (let l of lines) this.onLine(l);
        });
        // f.on('error', ()=>{});
        f.on('end', ()=>{console.log('chars', this.totalChars, 'lines', this.totalLines)});
    }
    onLine(l){
        this.emit('line', l);
    }
}
//Command line test
const f = require('fs').createReadStream(process.argv[2], 'utf8');
const delim = process.argv[3];
const lineReader = new LineReader(f, delim);
lineReader.on('line', (line)=> console.log(line));

Вот еще более короткая версия без статистики в 19 строк:

class LineReader extends require('events').EventEmitter{
    constructor(f, delim='\n'){
        super();
        this.leftover = '';
        f.on('data', (chunk)=>{
            let lines = chunk.split(delim);
            if (lines.length === 1){
                this.leftover += chunk;
                return;
            }
            lines[0] = this.leftover + lines[0];
            this.leftover = lines[lines.length-1];
            if (this.leftover) 
                lines.pop();
            for (let l of lines)
                this.emit('line', l);
        });
    }
}
0 голосов
/ 11 февраля 2013

Я использую это:

function emitLines(stream, re){
    re = re && /\n/;
    var buffer = '';

    stream.on('data', stream_data);
    stream.on('end', stream_end);

    function stream_data(data){
        buffer += data;
        flush();
    }//stream_data

    function stream_end(){
        if(buffer) stream.emmit('line', buffer);
    }//stream_end


    function flush(){
        var re = /\n/;
        var match;
        while(match = re.exec(buffer)){
            var index = match.index + match[0].length;
            stream.emit('line', buffer.substring(0, index));
            buffer = buffer.substring(index);
            re.lastIndex = 0;
        }
    }//flush

}//emitLines

используйте эту функцию в потоке и слушайте события линии, которые будут излучать.

gr-

...