как использовать NodeJS для чтения большого текстового файла в кодировке utf-8 - PullRequest
1 голос
/ 14 апреля 2020

есть много ответов о том, как использовать NodeJS для чтения текстового файла в кодировке utf-8; Однако мой вопрос заключается в том, как читать большие файлы. здесь «БОЛЬШОЙ» означает превышение возможностей памяти, например, 64 ГБ.

говорят, что у нас есть файл 64 ГБ JSON, где файл содержит символы utf-8; как получить значение pathKey как locale.ja.test = 測定; например, если у нас есть JSON объект типа { "a": { "b": { "c": 1 } } }, значение для pathKey a.b.c относится к значению 1.

, если это текст в кодировке ascii, мы можем просто разбить файл на части; например, мы читаем файл размером 100 МБ на 100 МБ и используем такой синтаксический анализатор, как parse(previousStat, block) -> stat; но для текста в кодировке utf-8 проблема заключается в том, что, если мы разделим файл на части, для некоторого углового случая мы можем разделить символ на 2 блока. как ...\0x88\0x12... -> [...\x88], [\x12...].

как правильно читать большие текстовые файлы в кодировке utf-8? Спасибо!

обратите внимание, что: JSON файл может быть записан в одну строку, что означает, что readline может не помочь.

аналогичный вопрос без ответов:

1 Ответ

0 голосов
/ 14 апреля 2020

после некоторых проб и ошибок я нашел одно решение:

для большого файла, нам нужно использовать stream: например, fs.createReadStream('...')

для юникода, нам нужно чтобы использовать флаг encoding: fs.createReadStream('/path/to/file', { encoding: 'utf8', fd: null })

для подсчета байтовой позиции, нам нужно преобразовать его в буфер, как Buffer.from(stream.read()).length

полный пример для индексации текстового файла в 3-GRAM и 2-GRAM:

Это тест -> [Thi, his, is , s i, is , s t, te, tes, est] и [Th, hi, is, s , i, is, s , t, te, es, st]

const i_s = require('stream');
const i_fs = require('fs');

function buildIndexer(I) {
   // I = { indexStat: { cur: 0, gram: [] }, index: { gram2: {}, gram3: {} } }
   return i_s.Transform({
      transform: (chunk, _encoding, next) => {
         // _encoding should be 'utf8'
         const N = chunk.length;
         for (let i = 0; i < N; i++) {
            const ch = chunk[i];
            const len = Buffer.from(ch).length;
            I.indexStat.gram.push(ch);
            let gn = I.indexStat.gram.length - 1;
            if (gn > 3) {
               I.indexStat.gram.shift();
               gn --;
            }
            if (gn >= 2) {
               const g2 = `${I.indexStat.gram[gn-2]}${I.indexStat.gram[gn-1]}`;
               I.index.gram2[g2] = I.index.gram2[g2] || [];
               I.index.gram2[g2].push(I.indexStat.cur - Buffer.from(g2).length);
            }
            if (gn >= 3) {
               const g3 = `${I.indexStat.gram[gn-3]}${I.indexStat.gram[gn-2]}${I.indexStat.gram[gn-1]}`;
               I.index.gram3[g3] = I.index.gram3[g3] || [];
               I.index.gram3[g3].push(I.indexStat.cur - Buffer.from(g3).length);
            }
         next(null, chunk);
      },
      decodeStrings: false,
      encoding: 'utf8',
   });
}

const S = i_fs.createReadStream('/path/to/file', { encoding: 'utf8', fd: null });
const I = { indexStat: { cur: 0, gram: [] }, index: { gram2: {}, gram3: {} } }
const T = buildIndexer(I);
S.pipe(T);
S.on('finish', () => S.close());
T.on('finish', () => console.log(I.index));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...