问题描述
https://nodejs.org/api/readline.html
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)并且将其加载到内存中会导致内存问题。
解决方法
新行只是一个字符(如果您在 Windows 上,则为两个字符),如果不处理文件,您将无法知道这些字符的位置。
然而,您只能读取文件中的某个字节范围。如果您知道每行包含 64 个字节的事实,您可以通过从第 6400 字节开始读取来跳过前 100 行,通过在第 12800 字节停止读取,您只能读取 100 行。
createReadStream
文档中提供了有关如何指定起点和终点的详细信息。
但我不想从头到尾读取整个文件,而是其中的一部分表示从第 1 行到 10000、20000 到 30000 等。
除非你的行是固定的、相同的长度,否则没有办法知道第 10,000 行从哪里开始而不从文件的开头读取并计算行数直到你到达第 10,000 行。这就是带有可变长度行的文本文件的工作方式。文件中的行不是文件系统知道的物理结构。对于文件系统来说,文件只是一个巨大的数据块。行的概念是我们在更高层次上发明的,因此文件系统或操作系统对行一无所知。知道行在哪里的唯一方法是读取数据并通过搜索行分隔符将其“解析”为行。因此,只有从文件开头搜索第 10,000 行分隔符并计数,才能找到第 10,000 行。
没有办法绕过它,除非您将文件预处理为更有效的格式(如数据库)或创建行位置索引。
基本上,我希望能够为我的函数的给定运行设置“开始”和“结束”行。
唯一的方法是提前“索引”数据,这样您就已经知道每一行的开始/结束位置。一些用于处理非常大文件的文本编辑器会执行此操作。他们通读文件(可能是懒惰地)读取每一行,并建立一个内存索引,表示每行开始的文件偏移量。然后,他们可以通过查询索引并从文件中读取该组数据来检索特定的行块。
这对 readline 和 fs.createReadStream 是否可行?
没有固定长度的行,如果不从头开始计算,就无法知道 10,000 行在文件中的哪个位置。
这是一个大文件(大约 1 GB)并且将其加载到内存中会导致内存问题。
使用 linereader 模块或其他执行类似操作的模块一次一行地流式传输文件将很好地处理内存问题,以便在任何给定时间只有来自文件的一个数据块在内存中。即使在一个小的内存系统中,您也可以通过这种方式处理任意大的文件。