在Node JS中只读取文件第一行的最有效方法是什么?

Pen*_*ica 9 javascript filesystems stream text-files node.js

想象一下,您有许多长文本文件,并且您只需要从每个文本的第一行提取数据(不读取任何其他内容).Node JS中最好的方法是什么?

谢谢!

Vik*_*tov 11

对于这种情况,几乎有一个内置模块 - readline. 它避免弄乱块等。代码如下所示:

const fs = require('fs');
const readline = require('readline');

async function getFirstLine(pathToFile) {
  const readable = fs.createReadStream(pathToFile);
  const reader = readline.createInterface({ input: readable });
  const line = await new Promise((resolve) => {
    reader.on('line', (line) => {
      reader.close();
      resolve(line);
    });
  });
  readable.close();
  return line;
}
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于零长度文件。该承诺将永远等待解决调用。 (3认同)
  • @nkhil这是我自己的错,当前的示例没有竞争条件。我一定是错过了await关键字,这是意料之外的。如果只返回promise并在reader.close()之后立即调用reader.close()会更简单。这将避免带来编译时相当繁重的等待逻辑。但这在这一点上是挑剔的。主要的问题仍然是,如果没有行可读取,它将永远挂起。 (2认同)

Pen*_*ica 8

我最终采用了这个解决方案,这似乎是迄今为止我见过的最高效的解决方案:

var fs = require('fs');
var Q = require('q');

function readFirstLine (path) {
  return Q.promise(function (resolve, reject) {
    var rs = fs.createReadStream(path, {encoding: 'utf8'});
    var acc = '';
    var pos = 0;
    var index;
    rs
      .on('data', function (chunk) {
        index = chunk.indexOf('\n');
        acc += chunk;
        index !== -1 ? rs.close() : pos += chunk.length;
      })
      .on('close', function () {
        resolve(acc.slice(0, pos + index));
      })
      .on('error', function (err) {
        reject(err);
      })
  });
}
Run Code Online (Sandbox Code Playgroud)

为方便起见,我创建了一个npm模块,命名为" firstline ".

感谢@dandavis的使用建议String.prototype.slice()!


538*_*MEO 7

我知道这并不能完全回答问题,但对于那些正在寻找一种可读简单的方法的人来说:

const fs = require('fs').promises;

async function getFirstLine(filePath) {
    const fileContent = await fs.readFile(filePath, 'utf-8');
    return (fileContent.match(/(^.*)/) || [])[1] || '';
} 

Run Code Online (Sandbox Code Playgroud)

笔记

  • 当然,这只适用于文本文件,我假设您从描述中使用了文本文件
  • 适用于空文件并返回空字符串
  • 这个正则表达式非常高效,因为它很简单(没有OR条件或复杂的匹配)并且只读取第一行

  • @harscoet我认为这对于那些来寻找简单解决方案的人来说可能很有用。起初我来这里是为了寻找类似的东西,但没有找到。我还将写一个更明确的免责声明:) (5认同)