Node.js:如何在写入流上写()完成'事件

时间:2015-01-19 20:24:50

标签: javascript node.js stream

我使用Node.js流逐行浏览文本文件,进行一些转换并输出到SVG文件。

我正在尝试在处理完成后编写最后一段数据(</svg>),但是当写入流发出finish事件时,尝试write()将会抛出Error: write after end

我能用优雅的方式解决这个问题吗?

注意:输入文件很大(大约1GB),因此{/ 1}}方法由于其I / O和内存管理而无法解决。

pipe()

解决方案

谢谢Jordan&amp; pNre帮助我解决这个问题。

解决方案1(通用)

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()

解决方案2(特定于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

4 个答案:

答案 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)