【问题标题】:Read from Nth to Mth line of text file in Node.js在 Node.js 中从第 N 行读取到第 M 行文本文件
【发布时间】:2019-12-06 10:57:09
【问题描述】:

虽然我找到了很多关于逐行读取文本文件或读取第 N 行的示例,但我找不到任何关于如何从第 N 行读取到第 M 行的示例。

文件有点大,约 5 GB(约 1000 万行)。

编辑:线条没有固定长度。

【问题讨论】:

    标签: node.js file text line


    【解决方案1】:

    您可以使用 readline 功能将文件作为流读取,而无需将其整体加载到 RAM。这是一个如何完成的示例:

    const fs = require('fs');
    const readline = require('readline');
    
    function readFromN2M(filename, n, m, func) {
      const lineReader = readline.createInterface({
        input: fs.createReadStream(filename),
      });
    
      let lineNumber = 0;
    
      lineReader.on('line', function(line) {
        lineNumber++;
        if (lineNumber >= n && lineNumber < m) {
          func(line, lineNumber);
        }
      });
    }
    

    让我们试试吧:

    // whatever you would like to do with those lines
    const fnc = (line, number) => {
      // e.g. print them to console like this:
      console.log(`--- number: ${number}`);
      console.log(line);
    };
    
    // read from this very file, lines from 4 to 7 (excluding 7):
    readFromN2M(__filename, 4, 7, fnc);
    

    这给出了输出:

    //  --- number: 4
    //  function readFromN2M(filename, n, m, func) {
    //  --- number: 5
    //    const lineReader = readline.createInterface({
    //  --- number: 6
    //      input: fs.createReadStream(filename),
    

    行从 1 开始编号。要从 0 开始,只需稍微修改编号即可。

    更新:

    我刚刚意识到,从某种意义上说,这种方法并不是 100% 安全的,如果某个文件没有以换行符结尾,那么这种文件的最后一行就不会以这种方式读取。这就是 readline 的设计方式......为了克服这个问题,我会以更复杂的方式准备文件流 - 通过在需要时向这些流添加新的行字符。这将使解决方案更长一些。但一切皆有可能。

    更新 2

    正如您在评论中提到的那样,即使在已经找到所需的行之后,lineReader 也会继续遍历,这会减慢应用程序的速度。我认为我们可以这样阻止它:

    lineReader.on('line', function(line) {
      lineNumber++;
      if (lineNumber >= n && lineNumber < m) {
        func(line, lineNumber);
      }
    

    接下来的 3 行应该“很快”停止 lineReader,但不会立即停止,如 official docs 中所述

      if (lineNumber > m) {
        lineReader.close();
      }
    });
    

    我相信这应该可以解决问题。

    【讨论】:

    • 在阅读了所需的行之后,我注意到有延迟,我猜是因为 linereader 会一直持续到文件末尾。有没有办法摆脱这种无用的迭代?这样就完美了。
    • @plexus 我刚刚在答案中添加了更新 2 部分。希望这应该有效,但我自己没有检查过。请尝试一下。
    • 恐怕没有区别。要读取位于文件中间的 500 行,这两种方法都需要 ~35''。
    • 我会测量“线路消耗”部分所花费的时间 - 它可能没有优化吗?否则,我认为使用 readline 读取文件不会太慢。我会尝试不操作func = () =&gt; {},看看它是否仍然很慢......
    • @plexus 你明白了吗?如果速度慢真的是由于 readline 功能,那么我目前唯一能想到的让它更快的是 1)找到第 N 行开始和 M+1 行开始(或第 M 行结束)的位置 - 并在尽可能精简的方式,然后 2)创建偏移量等于第 N 行开头的读取流,从而完全跳过 readline 对所有先前行的发射,然后 3)以与我们之前相同的方式使用这样一个缩短的流 -带阅读线。
    猜你喜欢
    • 1970-01-01
    • 2018-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-27
    • 2018-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多