成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何在Node.js中流式處理大JSON文件

開發(fā) 前端
本文介紹一個概念 SAX 的設(shè)計模式,這個概念雖然不是來源于 Node.js,但它解決問題的一些思想當(dāng)我們在使用 Node.js 或一些其它的編程語言中遇到類似問題時也會受到一些啟發(fā)。

解決一個問題不只要搜尋最終的答案,尋找答案的過程同樣也是重要的,善于思考與總結(jié)總歸是好的。

本文介紹一個概念 SAX 的設(shè)計模式,這個概念雖然不是來源于 Node.js,但它解決問題的一些思想當(dāng)我們在使用 Node.js 或一些其它的編程語言中遇到類似問題時也會受到一些啟發(fā),本文后面會介紹如何流式處理一個大 JSON 文件,下面先給出了兩個問題,可以先思考下如果是你會怎么做?

場景描述

問題一:假設(shè)現(xiàn)在有一個場景,有一個大的 JSON 文件,需要讀取每一條數(shù)據(jù)經(jīng)過處理之后輸出到一個文件或生成報表數(shù)據(jù),怎么能夠流式的每次讀取一條記錄?

  1.   {"id": 1}, 
  2.   {"id": 2}, 
  3.   ... 

問題二:同樣一個大的 JSON 文件,我只讀取其中的某一塊數(shù)據(jù),想只取 list 這個對象數(shù)組怎么辦?

  1.  "list": [], 
  2.   "otherList": [] 

在 Node.js 中我們可以基于以下幾種方式讀取數(shù)據(jù),也是通常首先能夠想到的:

  • fs.readFile():這個是一次性讀取數(shù)據(jù)到內(nèi)存,數(shù)據(jù)量大了都占用到內(nèi)存也不是好辦法,很容易造成內(nèi)存溢出。
  • fs.createReadStream():創(chuàng)建一個可讀流,能解決避免大量數(shù)據(jù)占用內(nèi)存的問題,這是一個系統(tǒng)提供的基礎(chǔ) API 讀取到的是一個個的數(shù)據(jù)塊,因為我們的 JSON 對象是結(jié)構(gòu)化的,也不能直接解決上面提的兩個問題。
  • 還有一個 require() 也可以加載 JSON 文件,但是稍微熟悉點 Node.js CommonJS 規(guī)范的應(yīng)該知道 require 加載之后是會緩存的,會一直占用在服務(wù)的內(nèi)存里。

了解下什么是 SAX

SAX 是 Simple API for XML 的簡稱,目前沒有一個標準的 SAX 參考標準,最早是在 Java 編程語言里被實現(xiàn)和流行開的,以 Java 對 SAX 的實現(xiàn)后來也被認為是一種規(guī)范。其它語言的實現(xiàn)也是遵循著該規(guī)則,盡管每門語言實現(xiàn)都有區(qū)別,但是這里有一個重要的概念 “事件驅(qū)動” 是相同的。

實現(xiàn)了 SAX 的解析器擁有事件驅(qū)動那樣的 API,像 Stream 的方式來工作,邊讀取邊解析,用戶可以定義回調(diào)函數(shù)獲取數(shù)據(jù),無論 XML 內(nèi)容多大,內(nèi)存占用始終都會很小。

這對我們本節(jié)有什么幫助?我們讀取解析一個大 JSON 文件的時候,也不能把所有數(shù)據(jù)都加載到內(nèi)存里,我們也需要一個類似 SAX 這樣的工具幫助我們實現(xiàn)。

基于 SAX 的流式 JSON 解析器

這是一個流式 JSON 解析器 https://github1s.com/creationix/jsonparse 周下載量在 600 多萬,但是這個源碼看起來很難梳理。如果是學(xué)習(xí),推薦一個基于 SAX 的更簡單版本

https://gist.github.com/creationix/1821394 感興趣的可以看看。

JSON 是有自己的標準的,有規(guī)定的數(shù)據(jù)類型、格式。這個 JSON 解析器也是在解析到特定的格式或類型后觸發(fā)相應(yīng)的事件,我們在使用時也要注冊相應(yīng)的回調(diào)函數(shù)。

下面示例,創(chuàng)建一個可讀流對象,在流的 data 事件里注冊 SaxParser 實例對象的 parse 方法,也就是將讀取到的原始數(shù)據(jù)(默認是 Buffer 類型)傳遞到 parse() 函數(shù)做解析,當(dāng)解析到數(shù)據(jù)之后觸發(fā)相應(yīng)事件。

對應(yīng)的 Node.js 代碼如下:

  1. const SaxParser = require('./jsonparse').SaxParser; 
  2. const p = new SaxParser({ 
  3.   onNull: function () { console.log("onNull") }, 
  4.   onBoolean: function (value) { console.log("onBoolean", value) }, 
  5.   onNumber: function (value) { console.log("onNumber", value) }, 
  6.   onString: function (value) { console.log("onString", value) }, 
  7.   onStartObject: function () { console.log("onStartObject") }, 
  8.   onColon: function () { console.log("onColon") }, 
  9.   onComma: function () { console.log("onComma") }, 
  10.   onEndObject: function () { console.log("onEndObject") }, 
  11.   onStartArray: function () { console.log("onEndObject") }, 
  12.   onEndArray: function () { console.log("onEndArray") } 
  13. }); 
  14.  
  15. const stream = require('fs').createReadStream("./example.json"); 
  16. const pparse = p.parse.bind(p); 
  17. stream.on('data', parse); 

怎么去解析一個 JSON 文件的數(shù)據(jù)已經(jīng)解決了,但是如果直接這樣使用還是需要在做一些處理工作的。

JSONStream 處理大文件

這里推薦一個 NPM 模塊 JSONStream,在它的實現(xiàn)中就是依賴的 jsonparse 這個模塊來解析原始的數(shù)據(jù),在這基礎(chǔ)之上做了一些處理,根據(jù)一些匹配模式返回用戶想要的數(shù)據(jù),簡單易用。

下面我們用 JSONStream 解決上面提到的兩個問題。

問題一:

假設(shè)現(xiàn)在有一個場景,有一個大的 JSON 文件,需要讀取每一條數(shù)據(jù)經(jīng)過處理之后輸出到一個文件或生成報表數(shù)據(jù),怎么能夠流式的每次讀取一條記錄?

因為測試,所以我將 highWaterMark 這個值調(diào)整了下,現(xiàn)在我們的數(shù)據(jù)是下面這樣的。

  1.   { "id": 1 }, 
  2.   { "id": 2 } 

重點是 JSONStream 的 parse 方法,我們傳入了一個 '.',這個 data 事件也是該模塊自己處理過的,每次會為我們返回一個對象:

  • 第一次返回 { id: 1 }
  • 第二次返回 { id: 2 }
  1. const fs = require('fs'); 
  2. const JSONStream = require('JSONStream'); 
  3.  
  4. (async () => { 
  5.   const readable = fs.createReadStream('./list.json', { 
  6.     encoding: 'utf8', 
  7.     highWaterMark: 10 
  8.   }) 
  9.   const parser = JSONStream.parse('.'); 
  10.   readable.pipe(parser); 
  11.   parser.on('data', console.log); 
  12. })() 

問題二:

同樣一個大的 JSON 文件,我只讀取其中的某一塊數(shù)據(jù),想只取 list 這個數(shù)組對象怎么辦?

解決第二個問題,現(xiàn)在我們的 JSON 文件是下面這樣的。

  1.   "list": [ 
  2.     { "name": "1" }, 
  3.     { "name": "2" } 
  4.   ], 
  5.   "other": [ 
  6.     { "key": "val" } 
  7.   ] 

與第一個解決方案不同的是改變了 parse('list.*') 方法,現(xiàn)在只會返回 list 數(shù)組,other 是不會返回的,其實在 list 讀取完成之后這個工作就結(jié)束了。

  • 第一次返回 { name: '1' }
  • 第二次返回 { name: '2' }
  1. (async () => { 
  2.   const readable = fs.createReadStream('./list.json', { 
  3.     encoding: 'utf8', 
  4.     highWaterMark: 10 
  5.   }) 
  6.   const parser = JSONStream.parse('list.*'); 
  7.   readable.pipe(parser); 
  8.   parser.on('data', console.log); 
  9. })(); 

總結(jié)

當(dāng)我們遇到類似的大文件需要處理時,盡可能避免將所有的數(shù)據(jù)存放于內(nèi)存操作,應(yīng)用服務(wù)的內(nèi)存都是有限制的,這也不是最好的處理方式。

文中主要介紹如何流式處理類似的大文件,更重要的是掌握編程中的一些思想,例如 SAX 一個核心點就是實現(xiàn)了 “事件驅(qū)動” 的設(shè)計模式,同時結(jié)合 Stream 做到邊讀取邊解析。

處理問題的方式是多樣的,還可以在生成 JSON 文件時做拆分,將一個大文件拆分為不同的小文件。

學(xué)會尋找答案,NPM 生態(tài)發(fā)展的還是不錯的,基本上你能遇到的問題大多已有一些解決方案了,例如本次問題,不知道如何使用 Stream 來讀取一個 JSON 文件時,可以在 NPM 上搜索關(guān)鍵詞嘗試著找下。

 

 

責(zé)任編輯:趙寧寧 來源: Nodejs技術(shù)棧
相關(guān)推薦

2021-07-15 10:15:52

Node.jsJSON前端

2021-07-30 11:20:53

JavaScriptNode.jsWeb Develop

2022-11-17 09:52:12

RHEL 9Node.js

2021-07-03 17:43:03

Node.jsNode變量

2020-08-05 08:31:51

SSL TLSNode.js

2020-10-26 08:34:13

Node.jsCORS前端

2011-09-09 14:23:13

Node.js

2023-10-04 07:35:03

2021-12-25 22:29:57

Node.js 微任務(wù)處理事件循環(huán)

2020-08-24 08:07:32

Node.js文件函數(shù)

2020-05-29 15:33:28

Node.js框架JavaScript

2022-08-12 07:01:00

Node.jsXSS腳本

2021-10-25 09:00:37

Node.jsJS前端

2021-09-07 07:53:43

工具

2013-11-01 09:34:56

Node.js技術(shù)

2021-08-20 16:05:28

JavaScript node.js 應(yīng)用安全

2015-03-10 10:59:18

Node.js開發(fā)指南基礎(chǔ)介紹

2020-04-20 16:00:05

Node.js框架JavaScript

2011-09-08 13:46:14

node.js

2011-11-01 10:30:36

Node.js
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 精品欧美一区二区三区久久久 | 中文字幕在线视频免费视频 | 欧美成人一级 | 国产精品久久二区 | 国产高清精品一区二区三区 | 精品久久国产 | 国产精品视频一二三区 | 一区二区三区四区在线播放 | 草比av| 男人天堂av网 | 国产一二三区在线 | 久久久久国产 | 国产精品爱久久久久久久 | 久久精品国产99国产精品亚洲 | jav成人av免费播放 | 色欧美综合 | 久久精品免费看 | 亚洲综合天堂网 | 美女视频黄色片 | 天天操天天干天天爽 | 在线āv视频 | 成人激情视频免费在线观看 | 一级片在线观看 | 91精品久久久久久久99 | 亚洲精品一区二区 | 热久久免费视频 | 久久久久久久电影 | 国产成人免费 | 国产精品久久久久免费 | 九九热国产视频 | 亚洲视频一区在线观看 | 日韩插插 | 中国黄色毛片视频 | 国产精品一区二区三区在线 | 久久久成人一区二区免费影院 | 99国产视频 | 在线视频成人 | 欧美在线a| 天天综合网永久 | 凹凸日日摸日日碰夜夜 | 亚洲视频一区在线观看 |