синхронизация nodejs читать большой файл построчно? - PullRequest
9 голосов
/ 25 сентября 2011

У меня большой файл (utf8).Я знаю, fs.createReadStream может создать поток для чтения большого файла, но не синхронизируется.Поэтому я пытаюсь использовать fs.readSync, но чтение текста не работает, как "迈�".

var fs = require('fs');
var util = require('util');
var textPath = __dirname + '/people-daily.txt';   
var fd = fs.openSync(textPath, "r");
var text = fs.readSync(fd, 4, 0, "utf8");
console.log(util.inspect(text, true, null));

Ответы [ 5 ]

11 голосов
/ 19 января 2014

Для больших файлов readFileSync может быть неудобно, так как загружает весь файл в память. Другой синхронный подход заключается в итеративном вызове readSync, считывании небольших битов данных за раз и обработке строк по мере их поступления. Следующий фрагмент кода реализует этот подход и синхронно обрабатывает одну строку за раз из файла 'test.txt':

var fs = require('fs');
var filename = 'test.txt'

var fd = fs.openSync(filename, 'r');
var bufferSize = 1024;
var buffer = new Buffer(bufferSize);

var leftOver = '';
var read, line, idxStart, idx;
while ((read = fs.readSync(fd, buffer, 0, bufferSize, null)) !== 0) {
  leftOver += buffer.toString('utf8', 0, read);
  idxStart = 0
  while ((idx = leftOver.indexOf("\n", idxStart)) !== -1) {
    line = leftOver.substring(idxStart, idx);
    console.log("one line read: " + line);
    idxStart = idx + 1;
  }
  leftOver = leftOver.substring(idxStart);
}
7 голосов
/ 22 декабря 2015

использование https://github.com/nacholibre/node-readlines

var lineByLine = require('n-readlines');
var liner = new lineByLine('./textFile.txt');

var line;
var lineNumber = 0;
while (line = liner.next()) {
    console.log('Line ' + lineNumber + ': ' + line.toString('ascii'));
    lineNumber++;
}

console.log('end of line reached');
4 голосов
/ 25 сентября 2011

Использовать readFileSync :

fs.readFileSync (имя файла, [кодировка]) Синхронная версия fs.readFile. Возвращает содержимое имени файла.

Если задана кодировка, эта функция возвращает строку. В противном случае он возвращает буфер.

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

2 голосов
/ 09 сентября 2016

Я построил более простую версию ответа JB Kohn, которая использует split () в буфере.Он работает с большими файлами, которые я пробовал.

/*
 * Synchronously call fn(text, lineNum) on each line read from file descriptor fd.
 */
function forEachLine (fd, fn) {
    var bufSize = 64 * 1024;
    var buf = new Buffer(bufSize);
    var leftOver = '';
    var lineNum = 0;
    var lines, n;

    while ((n = fs.readSync(fd, buf, 0, bufSize, null)) !== 0) {
        lines = buf.toString('utf8', 0 , n).split('\n');
        lines[0] = leftOver+lines[0];       // add leftover string from previous read
        while (lines.length > 1) {          // process all but the last line
            fn(lines.shift(), lineNum);
            lineNum++;
        }
        leftOver = lines.shift();           // save last line fragment (may be '')
    }
    if (leftOver) {                         // process any remaining line
        fn(leftOver, lineNum);
    }
}
1 голос
/ 25 сентября 2011

две потенциальные проблемы,

  1. 3-байтовая спецификация в начале, которую вы не пропустили
  2. первые 4 байта не могут быть хорошо отформатированы для символов UTF8 (utf8 не фиксированной длины)
...