最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

在Nodejs中解析大型JSON文件

运维笔记admin15浏览0评论

在Nodejs中解析大型JSON文件

在Nodejs中解析大型JSON文件

我有一个文件,该文件以JSON形式存储许多JavaScript对象,我需要读取该文件,创建每个对象并对其进行处理(在我的情况下,将它们插入db中)。 JavaScript对象可以表示为以下格式:

格式A:

[{name: 'thing1'},
....
{name: 'thing999999999'}]

格式B:

{name: 'thing1'}         // <== My choice.
...
{name: 'thing999999999'}

请注意,...表示很多JSON对象。我知道我可以将整个文件读入内存,然后像这样使用JSON.parse()

fs.readFile(filePath, 'utf-8', function (err, fileContents) {
  if (err) throw err;
  console.log(JSON.parse(fileContents));
});

但是,文件可能很大,我希望使用流来完成此操作。我在流中看到的问题是文件内容随时都可能被分解成数据块,那么如何在此类对象上使用JSON.parse()

理想情况下,每个对象将作为一个单独的数据块读取,但是我不确定如何做到这一点

var importStream = fs.createReadStream(filePath, {flags: 'r', encoding: 'utf-8'});
importStream.on('data', function(chunk) {

    var pleaseBeAJSObject = JSON.parse(chunk);           
    // insert pleaseBeAJSObject in a database
});
importStream.on('end', function(item) {
   console.log("Woot, imported objects into the database!");
});*/

注意,我希望防止将整个文件读入内存。时间效率对我来说并不重要。是的,我可以尝试一次读取多个对象并一次插入所有对象,但这是性能上的调整-我需要一种方法来确保不会引起内存过载,无论文件中包含多少个对象。

我可以选择使用FormatAFormatB或其他方式,只需在您的答案中指定。谢谢!

回答如下:

要逐行处理文件,您只需要将文件的读取与作用于该输入的代码分离开。您可以通过缓冲输入直到碰到换行符来完成此操作。假设每行有一个JSON对象(基本上是格式B):

var stream = fs.createReadStream(filePath, {flags: 'r', encoding: 'utf-8'});
var buf = '';

stream.on('data', function(d) {
    buf += d.toString(); // when data is read, stash it in a string buffer
    pump(); // then process the buffer
});

function pump() {
    var pos;

    while ((pos = buf.indexOf('\n')) >= 0) { // keep going while there's a newline somewhere in the buffer
        if (pos == 0) { // if there's more than one newline in a row, the buffer will now start with a newline
            buf = buf.slice(1); // discard it
            continue; // so that the next iteration will start with data
        }
        processLine(buf.slice(0,pos)); // hand off the line
        buf = buf.slice(pos+1); // and slice the processed data off the buffer
    }
}

function processLine(line) { // here's where we do something with a line

    if (line[line.length-1] == '\r') line=line.substr(0,line.length-1); // discard CR (0x0D)

    if (line.length > 0) { // ignore empty lines
        var obj = JSON.parse(line); // parse the JSON
        console.log(obj); // do something with the data here!
    }
}

每次文件流从文件系统接收数据时,都会将其存储在缓冲区中,然后调用pump

如果缓冲区中没有换行符,则pump只会返回而不执行任何操作。下次流获取数据时,会将更多数据(可能还有换行符)添加到缓冲区,然后我们将有一个完整的对象。

[如果有换行符,则pump从开头到换行符将缓冲区切开,并将其交给process。然后,它再次检查缓冲区中是否还有换行符(while循环)。这样,我们可以处理在当前块中读取的所有行。

最后,process每条输入线被调用一次。如果存在,它将去除回车符(以避免出现行尾问题– LF vs CRLF),然后在行中调用JSON.parse。此时,您可以对对象进行任何操作。

请注意,JSON.parse对于接受的输入严格要求;您必须使用标识符标识符和字符串值双引号。换句话说,{name:'thing1'}将引发错误;您必须使用{"name":"thing1"}

因为一次内存中最多只能有一块数据,所以这将极大地提高内存效率。这也将非常快。快速测试显示,我在15毫秒内处理了10,000行。

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论