0

https://nodejs.org/api/readline.html

提供此解决方案,用于逐行读取 CSV 等大文件:

const { createReadStream } = require('fs');
const { createInterface } = require('readline');

(async function processLineByLine() {
  try {
    const rl = createInterface({
      input: createReadStream('big-file.txt'),
      crlfDelay: Infinity
    });

    rl.on('line', (line) => {
      // Process the line.
    });

    await once(rl, 'close');

    console.log('File processed.');
  } catch (err) {
    console.error(err);
  }
})();

但我不想从头到尾阅读整个文件,但其中的一部分是从第 1 行到第 10000、20000 到 30000 等。

基本上我希望能够为我的函数的给定运行设置一个“开始”和“结束”行。

这对readline&可行fs.createReadStream吗?如果没有,请建议替代方法。

PS:这是一个大文件(大约 1 GB)并将其加载到内存中会导致内存问题。

4

2 回答 2

1

但我不想从头到尾阅读整个文件,但其中的部分内容是从第 1 行到第 10000、20000 到 30000 等。

除非您的行是固定的、相同的长度,否则如果不从文件开头读取并计算行数,直到您到达第 10,000 行,就无法知道第 10,000 行从哪里开始。这就是具有可变长度行的文本文件的工作方式。文件中的行不是文件系统知道的任何物理结构。对于文件系统来说,文件只是一个巨大的数据块。行的概念是我们在更高层次上发明的,因此文件系统或操作系统对行一无所知。知道行在哪里的唯一方法是读取数据并通过搜索行分隔符将其“解析”成行。因此,只有从文件开头开始搜索第 10,000 行分隔符并计数,才能找到第 10,000 行。

没有办法绕过它,除非您将文件预处理为更有效的格式(如数据库)或创建行位置索引。

基本上我希望能够为我的函数的给定运行设置一个“开始”和“结束”行。

做到这一点的唯一方法是提前“索引”数据,这样您就已经知道每行的开始/结束位置。一些用于处理非常大文件的文本编辑器会这样做。他们通读文件(可能是懒惰地)读取每一行,并为每行开始的文件偏移量建立一个内存索引。然后,他们可以通过查询索引并从文件中读取该组数据来检索特定的行块。

这对 readline 和 fs.createReadStream 可行吗?

如果没有固定长度的行,如果不从头开始数,就无法知道文件中第 10,000 行从哪里开始。

这是一个大文件(大约 1 GB)并将其加载到内存中会导致内存问题。

使用 linereader 模块或执行类似操作的其他模块一次流式传输文件将很好地处理内存问题,以便在任何给定时间只有来自文件的数据块在内存中。即使在小型内存系统中,您也可以通过这种方式处理任意大的文件。

于 2021-07-01T01:38:29.040 回答
1

新行只是一个字符(如果您在 Windows 上,则为两个字符),如果不处理文件,您将无法知道这些字符的位置。

但是,您只能读取文件中的某个字节范围。如果您知道每行包含 64 个字节,则可以通过从 6400 字节开始读取来跳过前 100 行,并且可以通过在字节 12800 停止读取来仅读取 100 行。

createReadStream文档中提供了有关如何指定起点和终点的详细信息。

于 2021-06-30T21:37:14.120 回答