我使用Node.js流逐行浏览文本文件,进行一些转换并输出到SVG文件。
我正在尝试在处理完成后编写最后一段数据(</svg>
),但是当写入流发出finish
事件时,尝试write()
将会抛出Error: write after end
。
我能用优雅的方式解决这个问题吗?
注意:输入文件很大(大约1GB),因此{/ 1}}方法由于其I / O和内存管理而无法解决。
pipe()
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);
使用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>');
});
/ through
转换流) through2
有一个flush函数,可用于写入最终数据。
through2
答案 0 :(得分:8)
管道在完成后似乎会关闭它。
http://nodejs.org/api/stream.html州的文件:
默认情况下,当源流发送结束时,在目标上调用end(),以便该目标不再可写。传递{end:false}作为保持目标流开放的选项。
这使作家保持开放状态,以便最后可以写出“再见”。
reader.pipe(writer, { end: false });
reader.on('end', function() {
writer.end('Goodbye\n');
});
答案 1 :(得分:2)
您是否考虑过创建新流以附加</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);
答案 2 :(得分:1)
似乎有一个名为'prefinish'
的未记录事件。
我没有用过它。
答案 3 :(得分:0)
最近遇到了这个问题并找到了更优雅的解决方案。在本机变换流上有一个(井)记录的_flush
方法。
https://nodejs.org/api/stream.html#stream_transform_flush_callback
解决方案看起来像这样:
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)