如何通过node.js中的JSONStream模块解析一个大的、换行符分隔的JSON文件?
Posted
技术标签:
【中文标题】如何通过node.js中的JSONStream模块解析一个大的、换行符分隔的JSON文件?【英文标题】:how to parse a large, Newline-delimited JSON file by JSONStream module in node.js? 【发布时间】:2013-02-13 19:41:26 【问题描述】:我有一个大的 json 文件,它是换行符分隔的 JSON,其中多个标准 JSON 对象由额外的换行符分隔,例如
'name':'1','age':5
'name':'2','age':3
'name':'3','age':6
我现在在node.js中使用JSONStream来解析一个大的json文件,我之所以使用JSONStream是因为它是基于流的。
但是,示例中的两种解析语法都无法帮助我解析这个 json 文件,每行中都有单独的 JSON
var parser = JSONStream.parse(**['rows', true]**);
var parser = JSONStream.parse([**/./**]);
谁能帮帮我
【问题讨论】:
逐行读取文件并分别解析。 【参考方案1】:当文件足够小以适合内存时,这是另一种解决方案。它一次性读取整个文件,通过在换行符处拆分(删除末尾的空白行)将其转换为数组,然后解析每一行。
import fs from "fs";
const parsed = fs
.readFileSync(`data.jsonl`, `utf8`)
.split(`\n`)
.slice(0, -1)
.map(JSON.parse)
【讨论】:
请在代码中添加更多解释,帮助我们理解更多 完成,如果您需要更多信息,请告诉我。【参考方案2】:我创建了一个包@jsonlines/core
,它将jsonlines解析为对象流。
你可以试试下面的代码:
npm install @jsonlines/core
const fs = require("fs");
const parse = require("@jsonlines/core");
// create a duplex stream which parse input as lines of json
const parseStream = parse();
// read from the file and pipe into the parseStream
fs.createReadStream(yourLargeJsonLinesFilePath).pipe(parseStream);
// consume the parsed objects by listening to data event
parseStream.on("data", (value) =>
console.log(value);
);
请注意,parseStream
是标准节点双工流。
所以你也可以使用for await ... of
或者其他方式消费。
【讨论】:
【参考方案3】:如果您的文件不够大,这是一个简单但不高效的解决方案:
const fs = require('fs');
let rawdata = fs.readFileSync('fileName.json');
let convertedData = String(rawdata)
.replace(/\n/gi, ',')
.slice(0, -1);
let JsonData= JSON.parse(`[$convertedData]`);
【讨论】:
【参考方案4】:JSONstream 旨在解析单个巨大的 JSON 对象,而不是很多 JSON 对象。您想在换行符处拆分流,然后将它们解析为 JSON。
NPM 包split 声称可以进行这种拆分,甚至还有一个feature to parse the JSON lines 供您使用。
【讨论】:
我发现 split 包非常有用,事实上,使用 split+JSON.parse() 优于 JSONStream。【参考方案5】:警告:由于写了这个答案,JSONStream 库的作者removed the emit root event functionality,显然是为了修复内存泄漏。 该库的未来用户,如果您需要发出根功能,可以使用 0.x.x 版本。
以下是未经修改的原始答案:
来自readme:
JSONStream.parse(路径)
path
应该是属性名称、正则表达式、布尔值和/或函数的数组。任何与路径匹配的对象都将作为'data'
发出。当接收到所有数据时会发出
'root'
事件。'root'
事件传递根对象和匹配对象的计数。
在您的情况下,由于您想要取回 JSON 对象而不是特定属性,因此您将使用 'root'
事件并且您不需要指定路径。
您的代码可能如下所示:
var fs = require('fs'),
JSONStream = require('JSONStream');
var stream = fs.createReadStream('data.json', encoding: 'utf8'),
parser = JSONStream.parse();
stream.pipe(parser);
parser.on('root', function (obj)
console.log(obj); // whatever you will do with each JSON object
);
【讨论】:
注意 var 行末尾的错字 - ';'应该是','。 @frangio 如果需要读取大文件,请根据 OPs 问题澄清用法,但直接将 Objectified 流传递给管道中的下一个 Transform。例如。我想要 stream.pipe(parser).pipe(MyNextTransform) ,其中 MyNextTransform 可以处理它在 _transform() 方法中作为参数接收的对象。换句话说,希望 parser.on('root') 的输出被委托到另一个可读流上以进行进一步的管道处理。 没关系,我解决了 :) 只需返回 stream.pipe(parser),链中的下一个转换将自动给出 parser.on('root') 调用的结果.以上是关于如何通过node.js中的JSONStream模块解析一个大的、换行符分隔的JSON文件?的主要内容,如果未能解决你的问题,请参考以下文章
使用 JSONPath 和 JSONStream 解析 json 流
如何在 Node.js 中使用流对大型嵌套对象进行 JSON 字符串化?
如何将 Node.js 中的 net 模块与 browserify 一起使用?