我正在Dart中启动一个将stdout流附加到stdout的进程,以便可以将结果打印到终端,如下所示:
Process.start(executable, ['list','of','args']).then((proc) {
stdout.addStream(proc.stdout);
stderr.addStream(proc.stderr);
return proc.exitCode;
});
然而,一旦完成,我想开始一个新的过程并再次开始(这个函数将被调用几次)。有时,我收到一个错误:
Uncaught Error: Bad State: StreamSink is already bound to a stream
查看dart文档,看起来我可能需要执行stdout.close()
或stdout.flush()
之类的操作,但这些似乎无法解决问题。处理多个流顺序绑定到streamink的正确方法是什么?
答案 0 :(得分:4)
addStream
返回一个Future,指示何时完成流的添加。 addStream
只应该有一个StreamSink
同时出现的流。
根据您的需要/需要做什么,您现在有两个选择:
addStream
完成。后者更容易:
Process.start(executable, ['list','of','args']).then((proc) async {
await stdout.addStream(proc.stdout); // Edit: don't do this.
await stdout.addStream(proc.stderr);
return proc.exitCode;
});
请注意正文上的async
修饰符以及正文中的两个await
。
编辑:不立即收听stderr是错误的。 (你的程序可以阻止它。)
如果您的程序输出足够小,您可以切换到Process.run
:
Process.run(executable, ['list','of','args']).then((procResult) {
stdout.write(procResult.stdout);
stdout.write(procResult.stderr);
return procResult.exitCode;
});
但它不会交错stdout和stderr。
答案 1 :(得分:3)
您不能在同一个接收器上多次拨打addStream
。
接收器处于“手动”模式或“自动”模式,后者通过添加流来触发。在添加完流之前,暂停将路由到正在添加的流而不是路由器,并且在完成之前不允许手动添加事件。好像添加的流接管了接收器,直到完成为止。
要将两个(或更多)流添加到交错的同一个接收器,您必须手动执行此操作。一种方法是使用一种通用的方式来交错流,如下面的代码。另一个选择是自己监听两个流并将事件添加到接收器:
Stream interleave(Iterable<Stream> streams) {
List subscriptions = [];
StreamController controller;
controller = new StreamController(
onListen: () {
int active = 0;
void done() {
active--;
if (active <= 0) controller.close();
}
for (var stream in streams) {
active++;
var sub = stream.listen(controller.add,
onError: controller.addError,
onDone: done);
subscriptions.add(sub);
}
},
onPause: () {
for (var sub in subscriptions) { sub.pause(); }
},
onResume: () {
for (var sub in subscriptions) { sub.resume(); }
},
onCancel: () {
for (var sub in subscriptions) { sub.cancel(); }
}
);
return controller.stream;
}
(未经过彻底测试!)
答案 2 :(得分:0)
您也可以使用
StreamSubscription subscr = proc.stdout.listen(io.stdout.add);
...
subscr.cancel();
或使用可配置的处理程序
class StdOutHandler {
IOSink sink;
call(data) => sink.add();
}
void main() {
var proc = await Process.start(...);
var stdoutHandler = new StdOutHandler()..sink = stdout;
var subscription = proc.stdout.listen(stdoutHandler);
....
stdoutHandler.sink = ...
}