如何使用NodeJS读取大型utf-8编码的文本文件

问题描述 投票:1回答:1

关于如何使用NodeJS读取utf-8编码的文本文件有很多答案;但是,我的问题是如何读取大文件。在这里,“大”表示超出了存储能力,例如64GB。

说我们有一个64GB的JSON文件,其中文件包含utf-8字符;如何获得像locale.ja.test = 測定这样的pathKey值;例如,如果我们有像{ "a": { "b": { "c": 1 } } }这样的JSON对象,则pathKey a.b.c的值引用值1

如果是ascii编码的文本,我们可以简单地将文件分成几部分;例如,我们读取文件100MB x 100MB,并使用parse(previousStat, block) -> stat之类的解析器;但是对于utf-8编码的文本,问题在于,如果将文件分割成几个部分,对于某些特殊情况,我们可能会将一个字符分割成2个块。像...\0x88\0x12...-> [...\x88][\x12...]

如何正确读取大型utf-8编码的文本文件?谢谢!

注意:JSON文件可以写在一行中,这意味着readline可能无济于事。

类似的问题,没有答案:

node.js utf-8 text-processing
1个回答
0
投票

经过一番尝试和错误之后,我找出了一种解决方案:

对于大文件,我们需要使用stream:例如fs.createReadStream('...')

对于Unicode,我们需要使用标志encodingfs.createReadStream('/path/to/file', { encoding: 'utf8', fd: null })

为了计算字节位置,我们需要像Buffer.from(stream.read()).length那样将其转换为Buffer。>

在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));
© www.soinside.com 2019 - 2024. All rights reserved.