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

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

Я пытался:

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

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

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

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

Начиная с Node.js v0.12 и Node.js v4.0.0, существует стабильная версия.

модуль ядра. Вот самый простой способ прочитать строки из файла без каких-либо внешних модулей: используйте приведенный выше cmd для уничтожения определенного порта и запуска вашего сервера Последняя строка читается правильно (начиная с Node v0.12 или новее ), даже если окончательного

var lineReader = require('readline').createInterface({
  input: require('fs').createReadStream('file.in')
});

lineReader.on('line', function (line) {
  console.log('Line from file:', line);
});

нет: этот пример n Глядя на вывод

ОБНОВЛЕНИЕ был добавлен в официальную документацию API Node . Для такой простой операции не должно быть никакой зависимости от сторонних модулей. Полегче. Глядя на вывод

Вам не нужно

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

var rd = readline.createInterface({
    input: fs.createReadStream('/path/to/file'),
    output: process.stdout,
    console: false
});

rd.on('line', function(line) {
    console.log(line);
});

файл, но вместо этого вы должны создать open, а затем передать этот поток ReadStream Глядя на вывод

fs.createReadStream

, есть очень хороший модуль для чтения файла построчно, он называется Lazy

читатель строки с ним вы просто пишете:

вы можете даже перебрать файл с помощью интерфейса «в стиле java», если вам нужен больший контроль:

var lineReader = require('line-reader');

lineReader.eachLine('file.txt', function(line, last) {
  console.log(line);
  // do whatever you want with line...
  if(last){
    // or check if it's the last one
  }
});

Старая тема, но это работает:

lineReader.open('file.txt', function(reader) {
  if (reader.hasNextLine()) {
    reader.nextLine(function(line) {
      console.log(line);
    });
  }
});
require('fs').readFileSync('file.txt', 'utf-8').split(/r?n/).forEach(function(line){
  console.log(line);
})

Просто. Нет необходимости во внешнем модуле.

var rl = readline.createInterface({
      input : fs.createReadStream('/path/file.txt'),
      output: process.stdout,
      terminal: false
})
rl.on('line',function(line){
     console.log(line) //or parse line
})

Просто. Нет необходимости во внешнем модуле.

Вы всегда можете свернуть свой собственный читатель строки. Я пока не тестировал этот фрагмент, но он правильно разбивает входящий поток кусков на строки без завершающего ‘ n’

var last = "";

process.stdin.on('data', function(chunk) {
    var lines, i;

    lines = (last chunk).split("n");
    for(i = 0; i < lines.length - 1; i  ) {
        console.log("line: "   lines[i]);
    }
    last = lines[i];
});

process.stdin.on('end', function() {
    console.log("line: "   last);
});

process.stdin.resume();

, я придумал это при работе над сценарием быстрого анализа журнала, который должен был накапливать данные во время анализ лога, и я чувствовал, что было бы неплохо попробовать сделать это, используя js и node вместо использования perl или bash.

В любом случае, я чувствую, что небольшие скрипты nodejs должны быть автономными и не полагаться на сторонние модули, поэтому после прочтения всех ответов на этот вопрос, каждый из которых использует различные модули для обработки разборов строк, решение 13 SLOC для нативных nodejs может быть представляет интерес .

С помощью модуль-носитель :

var carrier = require('carrier');

process.stdin.resume();
carrier.carry(process.stdin, function(line) {
    console.log('got one line: '   line);
});

Я закончил с массивной утечкой памяти, используя Lazy для чтения построчно при попытке затем обработать эти строки и записать их в другой поток из-за того, как работает сток / пауза / возобновление в узле (см .: http://elegantcode.com/2011/04/06/taking-baby-steps-with-node-js-pumping-data-between-streams/ (кстати, я люблю этого парня) ). Я не достаточно внимательно посмотрел на Lazy, чтобы понять, почему именно, но я не мог приостановить поток чтения, чтобы обеспечить утечку без выхода Lazy.

Я написал код для обработки массивных CSV-файлов в XML-документах, вы можете увидеть код здесь: https://github.com/j03m/node-csv2xml

Если вы запускаете предыдущие ревизии с Lazy линия утечки. Последняя версия вообще не имеет утечки, и вы, вероятно, можете использовать ее в качестве основы для считывателя / процессора. Хотя у меня есть кое-какие нестандартные вещи.

Редактировать: я думаю, я должен также отметить, что мой код с Lazy работал нормально, пока я не обнаружил, что пишу достаточно большие фрагменты xml, которые истощают / приостанавливают / возобновляют, потому что это необходимо. Для небольших кусков это было хорошо.

Мы только что выпустили

Использование преобразование потока Глядя на вывод


С помощью BufferedReader вы можете читать строки.

new BufferedReader ("lorem ipsum", { 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 ();

После публикации моего исходного ответа я обнаружил, что split — очень простой в использовании модуль узла для чтения строк в файле ;, который также принимает необязательные параметры.

var split = require('split');
fs.createReadStream(file)
    .pipe(split())
    .on('data', function (line) {
      //each chunk now is a seperate line! 
    });

Не тестировался на очень больших файлах. Дайте нам знать, если вы делаете.

я был разочарован отсутствием комплексного решения для этого, поэтому я собрал свою собственную попытку ( ссылается на окно. / npm ). Список возможностей, вставленный при копировании:

  • Интерактивная обработка строк (на основе обратного вызова, без загрузки всего файла в ОЗУ)
  • При желании можно вернуть все строки в массиве (подробный или необработанный режим)
  • Поток интерактивного прерывания, или выполнить обработку, подобную карте / фильтру
  • Обнаружить любое соглашение о новой строке (PC / Mac / Linux)
  • Правильная обработка eof / last line
  • Правильная обработка многобайтовых символов UTF-8
  • Получить смещение байта и информация о длине байта для каждой строки
  • Произвольный доступ с использованием линейных или байтовых смещений
  • Автоматическое отображение информации о смещении строки для ускорения произвольного доступа
  • Нулевые зависимости
  • причин

NIH? Вы решаете :-)

function createLineReader(fileName){
    var EM = require("events").EventEmitter
    var ev = new EM()
    var stream = require("fs").createReadStream(fileName)
    var remainder = null;
    stream.on("data",function(data){
        if(remainder != null){//append newly received data chunk
            var tmp = new Buffer(remainder.length data.length)
            remainder.copy(tmp)
            data.copy(tmp,remainder.length)
            data = tmp;
        }
        var start = 0;
        for(var i=0; i<data.length; i  ){
            if(data[i] == 10){ //n new line
                var line = data.slice(start,i)
                ev.emit("line", line)
                start = i 1;
            }
        }
        if(start<data.length){
            remainder = data.slice(start);
        }else{
            remainder = null;
        }
    })

    stream.on("end",function(){
        if(null!=remainder) ev.emit("line",remainder)
    })

    return ev
}


//---------main---------------
fileName = process.argv[2]

lineReader = createLineReader(fileName)
lineReader.on("line",function(line){
    console.log(line.toString())
    //console.log("                    ")
})

В большинстве случаев этого должно быть достаточно:

const fs = require("fs")

fs.readFile('./file', 'utf-8', (err, file) => {
  const lines = file.split('n')

  for (let line of lines)
    console.log(line)
});

Я хотел решить эту же проблему, в основном то, что было бы в Perl:

while (<>) {
    process_line($_);
}

, вы на самом деле создаете 2 события:

  • Минимальный синхронный код, который можно повторно использовать во многих проектах.
  • Нет ограничений на размер файла или количество строк.
  • Нет ограничений на длину строк.
  • Способен обрабатывать полный Юникод в UTF-8, включая символы за пределами BMP.
  • Способен обрабатывать * nix и окончания строк Windows (старый стиль Mac мне не нужен).
  • Символы конца строки должны быть включены в строки.
  • Может обрабатывать последнюю строку с символами конца строки или без них.
  • Не используйте внешние библиотеки, не включенные в дистрибутив node.js.

Это проект для меня, чтобы почувствовать низкоуровневый код типа сценариев в node.js и решить, насколько он жизнеспособен в качестве замены для других языков сценариев, таких как Perl.

После удивительных усилий и нескольких неудачных попыток, это код, который я придумал. Это довольно быстро, но менее тривиально, чем я ожидал: (разветвите его на GitHub)

var fs            = require('fs'),
    StringDecoder = require('string_decoder').StringDecoder,
    util          = require('util');

function lineByLine(fd) {
  var blob = '';
  var blobStart = 0;
  var blobEnd = 0;

  var decoder = new StringDecoder('utf8');

  var CHUNK_SIZE = 16384;
  var chunk = new Buffer(CHUNK_SIZE);

  var eolPos = -1;
  var lastChunk = false;

  var moreLines = true;
  var readMore = true;

  // each line
  while (moreLines) {

    readMore = true;
    // append more chunks from the file onto the end of our blob of text until we have an EOL or EOF
    while (readMore) {

      // do we have a whole line? (with LF)
      eolPos = blob.indexOf('n', blobStart);

      if (eolPos !== -1) {
        blobEnd = eolPos;
        readMore = false;

      // do we have the last line? (no LF)
      } else if (lastChunk) {
        blobEnd = blob.length;
        readMore = false;

      // otherwise read more
      } else {
        var bytesRead = fs.readSync(fd, chunk, 0, CHUNK_SIZE, null);

        lastChunk = bytesRead !== CHUNK_SIZE;

        blob  = decoder.write(chunk.slice(0, bytesRead));
      }
    }

    if (blobStart < blob.length) {
      processLine(blob.substring(blobStart, blobEnd   1));

      blobStart = blobEnd   1;

      if (blobStart >= CHUNK_SIZE) {
        // blobStart is in characters, CHUNK_SIZE is in octets
        var freeable = blobStart / CHUNK_SIZE;

        // keep blob from growing indefinitely, not as deterministic as I'd like
        blob = blob.substring(CHUNK_SIZE);
        blobStart -= CHUNK_SIZE;
        blobEnd -= CHUNK_SIZE;
      }
    } else {
      moreLines = false;
    }
  }
}

Вероятно, его можно было бы исправить и дальше, это было результатом проб и ошибок.

На основе генератора читатель строки: https://github.com/neurosnap/gen-readlines

var fs = require('fs');
var readlines = require('gen-readlines');

fs.open('./file.txt', 'r', function(err, fd) {
  if (err) throw err;
  fs.fstat(fd, function(err, stats) {
    if (err) throw err;

    for (var line of readlines(fd, stats.size)) {
      console.log(line.toString());
    }

  });
});

Если вы хотите построчно прочитать файл и записать его в другом:

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

function readFileLineByLine(inputFile, outputFile) {

   var instream = fs.createReadStream(inputFile);
   var outstream = new Stream();
   outstream.readable = true;
   outstream.writable = true;

   var rl = readline.createInterface({
      input: instream,
      output: outstream,
      terminal: false
   });

   rl.on('line', function (line) {
        fs.appendFileSync(outputFile, line   'n');
   });
};
var fs = require('fs');

function readfile(name,online,onend,encoding) {
    var bufsize = 1024;
    var buffer = new Buffer(bufsize);
    var bufread = 0;
    var fd = fs.openSync(name,'r');
    var position = 0;
    var eof = false;
    var data = "";
    var lines = 0;

    encoding = encoding || "utf8";

    function readbuf() {
        bufread = fs.readSync(fd,buffer,0,bufsize,position);
        position  = bufread;
        eof = bufread ? false : true;
        data  = buffer.toString(encoding,0,bufread);
    }

    function getLine() {
        var nl = data.indexOf("r"), hasnl = nl !== -1;
        if (!hasnl && eof) return fs.closeSync(fd), online(data,  lines), onend(lines); 
        if (!hasnl && !eof) readbuf(), nl = data.indexOf("r"), hasnl = nl !== -1;
        if (!hasnl) return process.nextTick(getLine);
        var line = data.substr(0,nl);
        data = data.substr(nl 1);
        if (data[0] === "n") data = data.substr(1);
        online(line,  lines);
        process.nextTick(getLine);
    }
    getLine();
}

У меня возникла та же проблема, и я придумал Приведенное выше решение выглядит симулированным для других, но является aSync и может очень быстро читать большие файлы

Надеюсь, это поможет

У меня есть небольшой модуль, который делает это хорошо и используется довольно многими другими проектами npm readline Обратите внимание, что в узле v10 есть собственный модуль readline, поэтому я переиздал свой модуль как linebyline https://www.npmjs.com/package/linebyline

, если вы не хотите использовать модуль, функция очень проста :

var fs = require('fs'),
EventEmitter = require('events').EventEmitter,
util = require('util'),
newlines = [
  13, // r
  10  // n
];
var readLine = module.exports = function(file, opts) {
if (!(this instanceof readLine)) return new readLine(file);

EventEmitter.call(this);
opts = opts || {};
var self = this,
  line = [],
  lineCount = 0,
  emit = function(line, count) {
    self.emit('line', new Buffer(line).toString(), count);
  };
  this.input = fs.createReadStream(file);
  this.input.on('open', function(fd) {
    self.emit('open', fd);
  })
  .on('data', function(data) {
   for (var i = 0; i < data.length; i  ) {
    if (0 <= newlines.indexOf(data[i])) { // Newline char was found.
      lineCount  ;
      if (line.length) emit(line, lineCount);
      line = []; // Empty buffer.
     } else {
      line.push(data[i]); // Buffer new line data.
     }
   }
 }).on('error', function(err) {
   self.emit('error', err);
 }).on('end', function() {
  // Emit last line if anything left over since EOF won't trigger it.
  if (line.length){
     lineCount  ;
     emit(line, lineCount);
  }
  self.emit('end');
 }).on('close', function() {
   self.emit('close');
 });
};
util.inherits(readLine, EventEmitter);

Другое решение — запустить логику через последовательного исполнителя 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 Обновление в 2019 году

Для этого требуется, чтобы на вашем компьютере была установлена ​​последняя версия Nodejs. & gt ; 11.4

Прекрасный пример уже опубликован в официальной документации Nodejs. говорится, что

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

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

async function processLineByLine() {
  const fileStream = fs.createReadStream('input.txt');

  const rl = readline.createInterface({
    input: fileStream,
    crlfDelay: Infinity
  });
  // Note: we use the crlfDelay option to recognize all instances of CR LF
  // ('rn') in input.txt as a single line break.

  for await (const line of rl) {
    // Each line in input.txt will be successively available here as `line`.
    console.log(`Line from file: ${line}`);
  }
}

processLineByLine();

, я использую этот атрибут:

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-

Хотя вам, вероятно, следует использовать модуль

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

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));

Я заключаю всю логику ежедневной обработки строк в npm module:

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);
        });
    }
}
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>';


});

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`)})

jquery — Когда JavaScript синхронен? — Переполнение стека

(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);

})();

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

const fs= require('fs')

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

stream.on('data', chunk => {
    let row = chunk.toString('ascii')
}))