Node.js可以同步或异步的方式逐行读取文件内容。其中,异步方式可以读取大型文件而不需要同时加载文件所有内容。

本文介绍4种逐行读取文件内容的Node.js操作,并做了性能测试,优劣评判。

准备

在写代码之前,要做以下准备:

  • 安装 Node.js 10
  • 熟悉NPM
  • 了解NodeJs事件驱动和非阻塞机制
  • 了解stream 流数据

测试文件

故意选了一个相对较大(90MB)、行数较多(798148 行)的 broadband.sql 文件,以便做性能测试。

同步方式

const fs = require('fs');

const allFileContents = fs.readFileSync('broadband.sql', 'utf-8');
allFileContents.split(/\r?\n/).forEach(line =>  {
  console.log(`Line from file: ${line}`);
});

const used = process.memoryUsage().heapUsed / 1024 / 1024;
console.log(`The script uses approximately ${Math.round(used * 100) / 100} MB`);

把文件读取内存之中,按行分割,循环打印各行。

执行脚本

node readfilesync.js

内存消耗200MB ,费时2-3分钟。

The script uses approximately 238.74 MB

如果文件大小1GB,不推荐使用同步读取的方式,内存消耗太大。

接下来,我们将研究一种更高效的异步方式,通过 readline 和另一个原生 Node.js 模块的 stream 逐行读取文件。

Readline

Readline 是Node.js原生模块,无需安装。它提供了用于从可读流(例如 process.stdin)每次一行地读取数据的接口。每当 input 流接收到行尾输入(\n、\r 或 \r\n)时,则会触发 ‘line’ 事件。

下面是带有可读流的 readline 的代码示例:

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

(async function processLineByLine() {
  try {
    const rl = readline.createInterface({
      input: fs.createReadStream('broadband.sql'),
      crlfDelay: Infinity
    });

    rl.on('line', (line) => {
      console.log(`Line from file: ${line}`);
    });

    await events.once(rl, 'close');

    console.log('Reading file line by line with readline done.');
    const used = process.memoryUsage().heapUsed / 1024 / 1024;
    console.log(`The script uses approximately ${Math.round(used * 100) / 100} MB`);
  } catch (err) {
    console.error(err);
  }
})();

理解一下以上代码:

首先引入Node.js的3个原生模块 events, fs, 和 readline。
•定义了一个名为 processLineByLine 的异步函数,它为 readline 创建了一个接口,其中输入是我们传递 90 MB 测试文件的读取流。
•设置为无穷大的 crlfDelay 。crlfDelay 如果 \r 和 \n 之间的延迟超过 crlfDelay 毫秒,则 \r 和 \n 都将被视为单独的行尾输入。 crlfDelay 将被强制为不小于 100 的数字。 它可以设置为 Infinity,在这种情况下,\r 后跟 \n 将始终被视为单个换行符(这对于具有 \r\n 行分隔符的文件读取可能是合理的)。 默认值: 100。
•在可读流交互时,每读取一行,就会触发 rl.on 读行函数。此时,就可以从流中读取的行的内容。
•然后我们用 events.once 监听 readline 关闭事件,它创建一个 Promise,该 Promise 将使用一个包含所有发送给给定事件的参数的数组来解析。在这种情况下,它将是一个空数组。
•最后记录内存使用情况

执行脚本

node readline.js

结果耗时很长(5-8分钟左右),内容占用率较低。

The script uses approximately 5.77 MB

N-readlines

N-readline 是一个 NPM 模块,它可以逐行读取文件,而不会将整个文件缓冲在内存中。它在不使用流的情况下,通过使用 Buffer 和本机文件系统模块以块的形式读取文件的内容。即使它以同步方式工作,它也不会将整个文件加载到内存中。

首先,安装 n-readlines 模块

npm i --save n-readlines:

通过N-readlines逐行读取文件如下:

const nReadlines = require('n-readlines');
const broadbandLines = new nReadlines('broadband.sql');

let line;
let lineNumber = 1;

while (line = broadbandLines.next()) {
    console.log(`Line ${lineNumber} has: ${line.toString('ascii')}`);
    lineNumber  ;
}

console.log('end of file.');
const used = process.memoryUsage().heapUsed / 1024 / 1024;
console.log(`The script uses approximately ${Math.round(used * 100) / 100} MB`);

以上代码相对较为简节。

•首先,引入 N-readlines 模块•创建一个读取文件的实例。默认参数是文件名, readChunk 和 newLineCharacter 可以作为第二个参数传入 。这里只使用文件名参数。•定义两个变量 line 和 lineNumber 。 Line 变量将保存文件每一行的字符串,而 lineNumber 将保存从 1 到文件行数的行号。•最后,文件读取结束之后打印出大概的内存使用情况。

执行脚本

node n-readlines.js

耗时巨长,内存消耗小。

The script uses approximately 4.09 MB

Line reader

Line reader 模块将自己定义为“支持用户定义的行分隔符的异步、缓冲、逐行文件/流读取器”。它提供 eachLine 函数读取给定文件的每一行。eachLine的回调函数中的last变量可用于确定是否已到达文件的最后一行。

下面是使用 line reader 读取我们相对较大的 90 MB SQL 文件的工作示例,我们使用 npm i –save line-reader 安装它。完整代码如下:

const lineReader = require('line-reader');

lineReader.eachLine('broadband.sql', function(line, last) {
  console.log(`Line from file: ${line}`);
  if(last) {
    console.log('Last line printed.');
    const used = process.memoryUsage().heapUsed / 1024 / 1024;
    console.log(`The script uses approximately ${Math.round(used * 100) / 100} MB`);
  }
});

代码解析

•首先,引入 line-reader 模块
•调用 eachLine 函数,将文件名(或文件路径)作为第一个参数传递。
•第2个参数是一个回调函数,包含 line 和 last 变量。
•在回调函数中打印行内容。
•最后,如果我们发现最后一个变量为真,这表明我们已经到达文件的末尾,打印出用于逐行读取文件的内存消耗。

执行脚本

node line-reader.js

时长感人,内存占用极少。

The script uses approximately 2.48 MB

其它方式

还有其他选项可以使用 Node.js 逐行读取文件。有一个非常流行的 NPM 模块叫做 readline ,但由于与原生 Node.js 模块的名称冲突,现在它已重命名为 Line By LIne。它的工作方式与本机 readline 模块非常相似

其他不太流行但可用的模块有 readline 和 readlines-ng,它们在每周仅被下载了大约 3 次。

使用JavaScript 数组函数,可以非常方便对于文件内容的进一步处理。

快速比较

在 NPM Trends 上对这四个 NPM 模块的快速比较显示,N-readlines 是下载量最大的模块,上周下载量为 56K。第二个是上周下载量为 46K 的 line-reader,但请记住 line-reader 最近一次更新是在 6 年前。以下是过去 1 年的下载快照:

推荐优先选择流行的类库,最近更新的类库是n-readlines,更新时间为1年前。

readline 和 readlines ng 的下载量约为每周 3 次,而 line reader 和 n-readlines 的下载量分别为 46K 和 56K。

在内存和 CPU 使用率方面,除了第一个 fs.readfilesync 之外的所有其他基于流或回调的方法,都消耗内存低于 10 MB ,并在 10 秒前完成,CPU 使用率为 70-94%。对于 90 MB 的文件,读取文件同步消耗了 225 MB 的内存。(实测,时间的消耗长达10几分钟的都有,可能是我电脑配置太低了)

总结

我们研究了如何在 Node.js 中逐行读取文件。这是个小问题,在 Node.js 中可以使用多种方法来解决。

我们还分析了 3 种方法中每种方法的内存使用情况和时间。

最后,我们快速比较了各类库的受欢迎程度,希望能对你有帮助。

补充

在此之前先介绍一个逐行读取文件内容NPM:https://github.com/nickewing/line-reader,需要的朋友可以看看。

直接上代码:

function readLines(input, func) {
  var remaining = '';
  input.on('data', function(data) {
    remaining  = data;
    var index = remaining.indexOf('\n');
    while (index > -1) {
      var line = remaining.substring(0, index);
      remaining = remaining.substring(index   1);
      func(line);
      index = remaining.indexOf('\n');
    }

  });

  input.on('end', function() {
    if (remaining.length > 0) {
      func(remaining);
    }
  });
}

function func(data) {
  container.push(data);
}

var input = fs.createReadStream(__dirname   '/ip_arr.txt');
readLines(input, func);

到此这篇关于node.js实现逐行读取文件内容的代码的文章就介绍到这了,更多相关node.js逐行读取文件内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

node.js实现逐行读取文件内容的代码的更多相关文章

  1. CentOS 8.2服务器上安装最新版Node.js的方法

    这篇文章主要介绍了CentOS 8.2服务器上安装最新版Node.js的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. node.js三个步骤实现一个服务器及Express包使用

    这篇文章主要介绍了node.js三个步骤实现一个服务器及Express包使用,文章通过新建一个文件展开全文内容,具有一定的参考价值,需要的小伙伴可以参考一下

  3. Node.js调试技术总结分享

    Node.js是一个可以快速构建网络服务及应用的平台。该平台的构建是基于Chrome's JavaScript runtime,也就是说,实际上它是对Google V8引擎(应用于Google Chrome浏览器)进行了封装。 今天介绍Node.js调式目前有几种技术,需要的朋友可以参考下。

  4. node.js实现http服务器与浏览器之间的内容缓存操作示例

    这篇文章主要介绍了node.js实现http服务器与浏览器之间的内容缓存操作,结合实例形式分析了node.js http服务器与浏览器之间的内容缓存原理与具体实现技巧,需要的朋友可以参考下

  5. 教你如何使用node.js制作代理服务器

    本文介绍了如何使用node.js制作代理服务器,图文并茂,十分的详细,代码很简洁易懂,这里推荐给大家。

  6. node.js中的fs.openSync方法使用说明

    这篇文章主要介绍了node.js中的fs.openSync方法使用说明,本文介绍了fs.openSync方法说明、语法、接收参数、使用实例和实现源码,需要的朋友可以参考下

  7. Node.js+ELK日志规范的实现

    这篇文章主要介绍了Node.js+ELK日志规范的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. node.js爬虫框架node-crawler初体验

    这篇文章主要介绍了node.js爬虫框架node-crawler的相关资料,帮助大家利用node.js进行爬虫,感兴趣的朋友可以了解下

  9. node.js中的fs.existsSync方法使用说明

    这篇文章主要介绍了node.js中的fs.existsSync方法使用说明,本文介绍了fs.existsSync方法说明、语法、接收参数、使用实例和实现源码,需要的朋友可以参考下

  10. 说说如何利用 Node.js 代理解决跨域问题

    这篇文章主要介绍了Node.js代理解决跨域问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

随机推荐

  1. Error: Cannot find module ‘node:util‘问题解决

    控制台 安装 Vue-Cli 最后一步出现 Error: Cannot find module 'node:util' 问题解决方案1.问题C:\Windows\System32>cnpm install -g @vue/cli@4.0.3internal/modules/cjs/loader.js:638 throw err; &nbs

  2. yarn的安装和使用(全网最详细)

    一、yarn的简介:Yarn是facebook发布的一款取代npm的包管理工具。二、yarn的特点:速度超快。Yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大化资源利用率,因此安装速度更快。超级安全。在执行代码之前,Yarn 会通过算法校验每个安装包的完整性。超级可靠。使用详细、简洁的锁文件格式和明确的安装算法,Yarn 能够保证在不同系统上无差异的工作。三、y

  3. 前端环境 本机可切换node多版本 问题源头是node使用的高版本

    前言投降投降 重头再来 重装环境 也就分分钟的事 偏要折腾 这下好了1天了 还没折腾出来问题的源头是node 使用的高版本 方案那就用 本机可切换多版本最终问题是因为nodejs的版本太高,导致的node-sass不兼容问题,我的node是v16.14.0的版本,项目中用了"node-sass": "^4.7.2"版本,无法匹配当前的node版本根据文章的提

  4. nodejs模块学习之connect解析

    这篇文章主要介绍了nodejs模块学习之connect解析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. nodejs npm package.json中文文档

    这篇文章主要介绍了nodejs npm package.json中文文档,本文档中描述的很多行为都受npm-config(7)的影响,需要的朋友可以参考下

  6. 详解koa2学习中使用 async 、await、promise解决异步的问题

    这篇文章主要介绍了详解koa2学习中使用 async 、await、promise解决异步的问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. Node.js编写爬虫的基本思路及抓取百度图片的实例分享

    这篇文章主要介绍了Node.js编写爬虫的基本思路及抓取百度图片的实例分享,其中作者提到了需要特别注意GBK转码的转码问题,需要的朋友可以参考下

  8. CentOS 8.2服务器上安装最新版Node.js的方法

    这篇文章主要介绍了CentOS 8.2服务器上安装最新版Node.js的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  9. node.js三个步骤实现一个服务器及Express包使用

    这篇文章主要介绍了node.js三个步骤实现一个服务器及Express包使用,文章通过新建一个文件展开全文内容,具有一定的参考价值,需要的小伙伴可以参考一下

  10. node下使用UglifyJS压缩合并JS文件的方法

    下面小编就为大家分享一篇node下使用UglifyJS压缩合并JS文件的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

返回
顶部