节点CSV拉解析器

时间:2018-04-10 08:56:10

标签: node.js csv parsing

我需要从Node.JS解析CSV文档,为每条记录(=每行)执行数据库操作。但是,我无法使用pull方法找到合适的CSV解析器,或者至少在解析下一行之前等待我的记录操作的推送方法。

我查看了csv-parsecsvtojsoncsv-streamify,但他们似乎都在连续流中推送事件而没有任何流量控制。如果解析1000行CSV文档,我基本上可以快速顺序获得所有1000个回调。对于每条记录,我执行一个返回承诺的操作。目前我不得不求助于将所有承诺推送到一个数组中,在获得done/end事件后,我也等待Promise.all(myOperations)知道文档何时完全处理。但这不是很好,而且,我更喜欢一次解析一行并完全处理它,然后获取下一条记录,而不是同时处理所有记录 - 它很难调试并使用大量内存而不是简单地按顺序处理每个记录。

那么,是否有一个支持拉模式的CSV解析器,或者是一种获取任何基于流的CSV解析器(最好是csvtojson的方式,因为我正在使用的那个)仅生成事件的方法我的前一个记录的处理程序完成后的新记录(使用promises)?

2 个答案:

答案 0 :(得分:0)

如果要异步处理每一行,可以使用节点的本地LineReader来执行此操作。

const lineStream = readline.createInterface({
  input: fs.createReadStream('data/test.csv'),
});

lineStream.on('line', (eachLine) =>{
    //process each line
});

如果您想以同步方式执行相同操作,可以使用line-by-line。它不会将整个文件缓冲到内存中。它提供事件处理程序来暂停和恢复“'发出事件。

lr.on('line', function (line) {
    // pause emitting of lines...
    lr.pause();

    // ...do your asynchronous line processing..
    setTimeout(function () {

        // ...and continue emitting lines. (1 sec delay)
        lr.resume();
    }, 1000);
});

答案 1 :(得分:0)

我自己通过创建自己的Writable来解决这个问题并将CSV解析器传递给它。我的write方法做了它的东西并包装传递给_write()的节点回调的承诺(这里使用Q.nodeify实现):

class CsvConsumer extends stream.Writable {
    _write(data, encoding, cb) {
        console.log('Got data: ', data);

        Q.delay(1000).then(() => {
            console.log('Waited 1 s');
        }).nodeify(cb);
    }
}

csvtojson()
    .fromStream(is)
    .pipe(new CsvConsumer())
    .on('finish', err => {
        if (err) {
            console.log('Error!');
        } else {
            console.log('Done!');
        }
    });

这将逐个处理行:

Got data: {"a": "1"}
Waited 1 s
Got data: {"a": "2"}
Waited 1 s
Got data: {"a": "3"}
Waited 1 s
Done!