javascript Node.js:如何在写入流“完成”事件上写入()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28032934/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Node.js: How to write() on Write Stream 'finish' event
提问by Dan Burzo
I'm using Node.js streams to go through a text file line by line, make some transforms and output to a SVG file.
我正在使用 Node.js 流逐行浏览文本文件,进行一些转换并输出到 SVG 文件。
I am trying to write one last piece of data (</svg>
) after the processing is done, however by the time the write stream emits the finish
event, attempting to write()
will throw Error: write after end
.
我试图</svg>
在处理完成后写入最后一条数据 ( ),但是当写入流发出finish
事件时,尝试write()
将抛出Error: write after end
.
Is there an elegant way I can solve this?
有没有一种优雅的方法可以解决这个问题?
Note:The input file is large (around 1GB) so there's no going around the pipe()
method due to its I/O and memory management.
注意:输入文件很大(大约 1GB),因此pipe()
由于其 I/O 和内存管理,无法绕过该方法。
var fs = require('fs');
var split2 = require('split2');
var through2 = require('through2');
var read_stream = fs.createReadStream('input.txt');
var write_stream = fs.createWriteStream('output.svg');
write_stream.write('<svg>');
write_stream.on('finish', function() {
this.write('</svg>'); // doesn't work
});
read_stream
.pipe(split2())
.pipe(through2.obj(function(line, encoding, next) {
this.push(line);
next();
}))
.pipe(write_stream);
Solutions
解决方案
Thank you Jordan& pNrefor helping me figuring this out.
Solution 1 (generic)
解决方案 1(通用)
pipe()
the write stream with the end:false
option and manually end()
the stream.
pipe()
带有end:false
选项的写流和手动end()
流。
var fs = require('fs');
var split2 = require('split2');
var through2 = require('through2');
var read_stream = fs.createReadStream('input.txt');
var write_stream = fs.createWriteStream('output.svg');
write_stream.write('<svg>');
read_stream
.pipe(split2())
.pipe(through2.obj(function(line, encoding, next) {
this.push(line);
next();
}))
.pipe(write_stream, { end: false });
read_stream.on('end', function() {
write_stream.end('</svg>');
});
Solution 2 (specific to through
/through2
transform streams)
解决方案2(特定于through
/through2
转换流)
through2
has a flush function that can be used to write the final data.
through2
有一个flush函数,可以用来写入最终数据。
var fs = require('fs');
var split2 = require('split2');
var through2 = require('through2');
var read_stream = fs.createReadStream('input.txt');
var write_stream = fs.createWriteStream('output.svg');
write_stream.write('<svg>');
read_stream
.pipe(split2())
.pipe(through2.obj(function(line, encoding, next) {
this.push(line);
next();
}, function(flush) {
this.push('</svg>');
flush();
}))
.pipe(write_stream);
回答by Jordan Honeycutt
It would seem that pipe closes the stream when it is finished.
管道似乎在完成时关闭了流。
The documentation at http://nodejs.org/api/stream.htmlstates:
http://nodejs.org/api/stream.html 上的文档指出:
By default end() is called on the destination when the source stream emits end, so that destination is no longer writable. Pass { end: false } as options to keep the destination stream open.
This keeps writer open so that "Goodbye" can be written at the end.
默认情况下,当源流发出 end 时,在目标上调用 end(),因此该目标不再可写。传递 { end: false } 作为保持目标流打开的选项。
这让作者保持开放,以便在最后写下“再见”。
reader.pipe(writer, { end: false });
reader.on('end', function() {
writer.end('Goodbye\n');
});
回答by pNre
Have you considered creating a new stream to append the </svg>
tag?
through
can help you with that:
您是否考虑过创建一个新流来附加</svg>
标签?
through
可以帮助您:
var fs = require('fs');
var split2 = require('split2');
var through = require('through');
var read_stream = fs.createReadStream('input.txt');
var write_stream = fs.createWriteStream('output.svg');
write_stream.write('<svg>');
var tag = through(function write(data) {
this.queue(data);
}, function end() {
this.queue('</svg>');
});
read_stream.pipe(split2()).pipe(some_transform).pipe(tag).pipe(write_stream);
回答by advncd
It seems that there is an un-documented event called 'prefinish'
.
I have not used it though.
似乎有一个未记录的事件称为'prefinish'
. 不过我没用过。
回答by THEtheChad
Recently ran in to this issue and found a more elegant solution. There's a (well) documented _flush
method on the native Transform stream.
最近遇到了这个问题,找到了一个更优雅的解决方案。_flush
本机 Transform 流上有一个(很好)记录的方法。
https://nodejs.org/api/stream.html#stream_transform_flush_callback
https://nodejs.org/api/stream.html#stream_transform_flush_callback
The solution looks something like this:
解决方案如下所示:
const fs = require('fs')
const split2 = require('split2')
const { Transform } = require('stream')
const input = fs.createReadStream('input.txt')
const output = fs.createWriteStream('output.svg')
class SVGWrapper extends Transform {
constructor(){ this.push('<svg>') }
_flush(done){ this.push('</svg>') }
_transform(line, enc, next){
this.push(line)
next()
}
}
input
.pipe(split2())
.pipe(new SVGWrapper)
.pipe(output)