我使用csv-to-json,一个整洁的库来处理CSV文件。
我有一个用例,我需要处理一个大的(> 2百万行)CSV并将其插入数据库。
为了在不遇到内存问题的情况下执行此操作,我打算将CSV作为流处理,每10000行暂停流,在我的数据库中插入行,然后恢复流。
由于某些原因,我似乎无法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中有多少行) - 我希望它不会记录任何内容,因为在将流传递给{{1}之前流已暂停}
答案 0 :(得分:2)
以下是图书馆创建者建议的解决方案,在此Issue中进行了跟踪:
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);
});
}
})
答案 1 :(得分:1)
除非修改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;
}
答案 2 :(得分:1)
我利用了csvtojson也有fromString(...)
方法的事实,并将其用于下面。
lr.pause()
暂停逐行阅读器。EOL
字符加入所有行,这将为您提供该CSV文件的10000行的字符串表示。.fromString(...)
将块的字符串表示转换为json对象并将其插入db。lr.resume()
重新开始播放,然后重复直到逐行阅读器发出'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");
});