所以我使用fs。readfile()它给了我
"致命错误:CALL_AND_RETRY_LAST分配失败-进程退出。记忆"
因为fs.readFile()在调用回调之前将整个文件加载到内存中,我应该使用fs.createReadStream()来代替吗?
这就是我之前对readFile:
所做的fs.readFile('myfile.json', function (err1, data) {
if (err1) {
console.error(err1);
} else {
var myData = JSON.parse(data);
//Do some operation on myData here
}
}
对不起,我对流媒体有点陌生;下面是正确的方法来做同样的事情,但与流媒体?
var readStream = fs.createReadStream('myfile.json');
readStream.on('end', function () {
readStream.close();
var myData = JSON.parse(readStream);
//Do some operation on myData here
});
谢谢
如果文件是巨大的,那么是的,流式传输将是您想要处理它的方式。然而,你在第二个例子中所做的是让流缓冲所有文件数据到内存中,然后在end
上处理它。在这一点上它和readFile
没有什么不同
你会想要检查JSONStream。流的意思是你想处理流经的数据。在您的情况下,显然您必须这样做,因为您不能一次将整个文件缓冲到内存中。考虑到这一点,希望这样的代码是有意义的:
JSONStream.parse('rows.*.doc')
注意它有一种查询模式。这是因为您不会同时处理文件中的整个JSON对象/数组,因此您必须更多地考虑JSONStream在发现时如何处理数据。
你可以使用JSONStream来查询你感兴趣的JSON数据。这样就不会将整个文件缓冲到内存中。它确实有缺点,如果你需要所有的数据,那么你将不得不多次流式传输文件,使用JSONStream只提取你需要的数据,但在你的情况下,你没有太多的选择。
你也可以使用JSONStream按顺序解析数据,并做一些事情,比如将其转储到数据库中。
JSONStream.parse
与JSON.parse
类似,但不是返回整个对象,而是返回一个流。当解析流获得足够的数据来形成与查询匹配的整个对象时,它将发出一个data
事件,其中的数据是与查询匹配的文档。一旦你配置了你的数据处理程序,你就可以将你的读流管道到解析流中,并观察奇迹发生。
的例子:
var JSONStream = require('JSONStream');
var readStream = fs.createReadStream('myfile.json');
var parseStream = JSONStream.parse('rows.*.doc');
parseStream.on('data', function (doc) {
db.insert(doc); // pseudo-code for inserting doc into a pretend database.
});
readStream.pipe(parseStream);
这是一种冗长的方式来帮助你理解发生了什么。下面是一种更简洁的方式:
var JSONStream = require('JSONStream');
fs.createReadStream('myfile.json')
.pipe(JSONStream.parse('rows.*.doc'))
.on('data', function (doc) {
db.insert(doc);
});
编辑:
为了更清楚地了解发生了什么,试着这样想。假设你有一个巨大的湖泊,你想对水进行处理,使其净化,并将水转移到一个新的水库。如果你有一架巨大的神奇直升机和一个大桶,那么你就可以飞越湖泊,把湖泊放在桶里,加入处理化学品,然后飞到目的地。
当然,问题是没有这样的直升机可以处理这么大的重量或体积。这是不可能的,但这并不意味着我们不能用另一种方式来实现我们的目标。因此,你在湖泊和新水库之间修建了一系列河流(小溪)。然后你在这些河流中建立净化站,净化流经河流的水。这些站点可以以多种方式运行。也许处理可以做得很快,你可以让河水自由流动,净化就会在水以最大速度流下来的时候发生。也可能需要一些时间来处理水,或者站需要一定量的水才能有效地处理水。所以你把河流设计成有闸门,控制湖水流入河流的流量,让水站缓冲它们所需要的水,直到它们完成任务,将纯净水释放到下游,并到达最终目的地。
这几乎就是你想对你的数据做的事情。解析流是您的清理站,它缓冲数据,直到有足够的数据形成与您的查询匹配的完整文档,然后将该数据向下游推送(并发出data
事件)。
节点流很好,因为大多数时候您不必处理打开和关闭闸门。节点流足够智能,可以在流缓冲一定数量的数据时控制回流。就好像净化站和湖上的闸门在互相交谈,以计算出最佳的流量。
如果你有一个流数据库驱动程序,那么理论上你可以创建某种插入流,然后执行parseStream.pipe(insertStream)
,而不是手动处理data
事件:下面是在另一个文件中创建JSON文件的过滤版本的示例。
fs.createReadStream('myfile.json')
.pipe(JSONStream.parse('rows.*.doc'))
.pipe(JSONStream.stringify())
.pipe(fs.createWriteStream('filtered-myfile.json'));