我有一个csv解析器实现为一系列转换流:
process.stdin
.pipe(iconv.decodeStream('win1252'))
.pipe(csv.parse())
.pipe(buildObject())
.pipe(process.stdout);
我想抽象解析器(在自己的模块中)并且能够做到:
process.stdin.
.pipe(parser)
.pipe(process.stdout);
其中parser
只是以前使用的变换流的组合。
如果我这样做
var parser = iconv.decodeStream('win1252')
.pipe(csv.parse())
.pipe(buildObject());
然后将parser
设置为buildObject()流,只有此转换流接收数据。
如果我这样做
var parser = iconv.decodeStream('win1252');
parser
.pipe(csv.parse())
.pipe(buildObject());
它也不起作用,因为.pipe(process.stdout)
将在第一个转换流上调用,另外两个将被绕过。
对流优雅组合的任何建议?
答案 0 :(得分:12)
不幸的是,没有内置的方法可以做到这一点,但有一个很酷的multipipe包。 使用方式如下:
var multipipe = require('multipipe');
var parser = multipipe(iconv.decodeStream('win1252'), csv.parse(), buildObject());
答案 1 :(得分:4)
我一直在努力解决这个问题(以及其他一些问题!)。我发现highlandjs几乎解决了我所有的问题。在这种情况下,他们的pipeline命令可以解决问题:
var h = require('highland');
var parser = h.pipeline(iconv.decodeStream('win1252'), csv.parse(), buildObject());
答案 2 :(得分:0)
我认为现在可以在本地完成。
const { PassThrough, Transform } = require('stream');
const compose = (...streams) => {
const first = new PassThrough();
const last = new PassThrough();
const result = new Transform();
[first, ...streams, last].reduce(
(chain, stream) => (
stream.on('error', (error) => result.emit('error', error)),
chain.pipe(stream)
),
);
result._transform = (chunk, enc, cb) => {
last.once('data', (chunk) => cb(null, chunk));
first.push(chunk, enc);
};
result._flush = (cb) => {
last.once('end', () => cb(null));
first.push(null);
};
return result;
};