[英]Pausing a readable stream in Node.js
我正在使用csv-to-json (一个简洁的库来处理CSV文件)。
我有一个用例,其中我需要处理大型(> 200万行)CSV并将其插入到数据库中。
为了做到这一点而不会遇到内存问题,我打算将CSV作为流进行处理,每10000行暂停该流,将这些行插入DB中,然后恢复该流。
由于某种原因,我似乎无法pause
流。
以下面的代码为例:
const rs = fs.createReadStream("./foo.csv");
rs.pause();
let count = 0;
csv()
.fromStream(rs)
.on("json", (json) => {
count++;
console.log(count);
})
.on("done", () => {
cb(null, count);
})
.on("error", (err) => {
cb(err);
})
count
被记录200次(这是我的CSV中有多少行)-我期望它不记录任何内容,因为流在将其传递给fromStream()
之前已暂停
这是库的创建者建议的解决方案,在本期中对此进行了跟踪:
var tmpArr=[];
rs.pipe(csv({},{objectMode:true})).pipe(new Writable({
write: function(json, encoding,callback){
tmpArr.push(json);
if (tmpArr.length===10000){
myDb.save(tmpArr,function(){
tmpArr=[];
callback();
})
}else{
callback();
}
} ,
objectMode:true
}))
.on('finish',function(){
if (tmpArr.length>0){
myDb.save(tmpArr,function(){
tmpArr=[];
})
}
})
我实际上已经设法像这样通过暂停来模拟暂停,但这并不理想:
let count = 0;
var csvParser=csv()
.fromStream(rs)
.on("json", (json) => {
rows.push(json);
if (rows.length % 1000 === 0) {
rs.unpipe();
// clear `rows` right after `unpipe`
const entries = rows;
rows = [];
this._insertEntries(db, entries, ()=> {
rs.pipe(csvParser);
});
}
})
我利用了csvtojson也具有fromString(...)
方法的事实,并按如下方式使用它。
lr.pause()
暂停逐行阅读器。 EOL
字符连接所有行,这将为您提供该CSV文件的10000行的字符串表示形式。 .fromString(...)
将block的字符串表示形式转换为json对象,并将其插入db中。 lr.resume()
恢复流,并重复直到逐行阅读器发出'end'
事件'end'
。 这是完整的代码
const CSVToJSON = require("csvtojson");
const LineByLineReader = require("line-by-line");
const { EOL } = require("os");
const BLOCK_LIMIT = 10000;
let lines = [];
let isFirstLineProcessed = false;
const lr = new LineByLineReader("./foo.csv");
lr
.on("line", (line) => {
// remove this if statement if your CSV does not contain headers line
if (!isFirstLineProcessed) {
isFirstLineProcessed = true;
return;
}
lines.push(line);
if (lines.length === BLOCK_LIMIT) {
lr.pause();
// insert headers string ("field1, field2, ...") at index 0;
lines.splice(0, 0, headers);
// join all lines using newline operator ("\n") to form a valid csv string
const csvBlockString = lines.join(EOL);
const entries = [];
lines = [];
csv()
.fromString(csvBlockString)
.on("json", (json) => {
entries.push(json);
})
.on("done", () => {
this._insertEntries(db, entries, ()=> {
lr.resume();
});
});
}
})
.on("end", () => {
console.log("done");
});
除非修改csv2json库,否则无法执行此操作。
这是您应该首先阅读的链接
https://nodejs.org/dist/latest-v6.x/docs/api/stream.html#stream_three_states
执行rs.pause()时,流处于暂停模式。 即使您不进行操作,实际上也会以暂停模式启动可读流。
该流在3种情况下进入resume
。
.on('data')
事件监听器,要么 .pipe()
方法或 readable.resume()
被显式调用。 在您的情况下, fromStream()
方法在您的可读流上附加了pipe
方法,从而恢复了该流。
参考代码:
https://github.com/Keyang/node-csvtojson/blob/master/libs/core/Converter.js#L378
Converter.prototype.fromStream=function(readStream,cb){
if (cb && typeof cb ==="function"){
this.wrapCallback(cb);
}
process.nextTick(function(){
readStream.pipe(this);
}.bind(this))
return this;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.