Node.js如何将gzip流管道到writeststream



我似乎不能让这个工作。我想写一些数据到gzip流,然后管道gzip流到文件写流。当文件完成写入时,我想调用一个函数。我现在有:

  var gz = zlib.createGzip()
               .pipe(fs.createWriteStream(gz_path));
  gz.write(data);
  gz.on('error', function(err){
    console.log("wtf error", err);
  });
  gz.on('finish', function(){
    console.log("write stream is done");
    dosomething();
  });

永远不调用完成事件或错误事件。

示例:

async function run(){
var zlib = require('zlib');
var fs = require("fs");
var gz = zlib.createGzip();
gz.on('error', function(err){    console.log(err.stack);   });
// gz.on('finish', function() {    console.log("finished compression, now need to finish writing...");   });
var f = fs.createWriteStream('test.txt.gz');
f.on('error', function(err){    console.log(err.stack);       });
f.on('finish', function() {    console.log("Write success.");   });
gz.pipe(f);
// if stream.write returns false need to wait for drain,
// for example using await for a promise in an async function, or maybe run the callback on drain
if(!gz.write('test','utf-8'))
  await new Promise( (resolve,reject)=> gz.once('drain', resolve) )
gz.end();
console.log("Compress zip file success.");
}
run();

问题中的代码有3个问题

  • 管道返回它的参数,而不是被调用的对象
  • 需要结束流,所以它会将数据写入输出
  • 最好在使用事件之前设置事件

// needded for code in question to run:
function dosomething(){
}
var gz_path="test.txt.gz"
var data="test"

//corrected code
var fs = require("fs");
var zlib = require('zlib');
// pipe retuns its argument, the folowing is correct:
// var f = zlib.createGzip().pipe(fs.createWriteStream(gz_path));
var gz = zlib.createGzip();
gz.pipe(fs.createWriteStream(gz_path));
// it helps to setup events before they fire  
gz.on('error', function(err){
    console.log("wtf error", err);
});
gz.on('finish', function(){
    console.log("write stream is done");
    dosomething();
});
gz.write(data);
// need to end stream for data to be written
gz.end()

try

var zlib = require('zlib');
var stream = require('stream');
var util = require('util');
var fs = require('fs');
var gz = zlib.createGzip();
function StringifyStream(){
    stream.Transform.call(this);
    this._readableState.objectMode = false;
    this._writableState.objectMode = true;
}
util.inherits(StringifyStream, stream.Transform);
StringifyStream.prototype._transform = function(obj, encoding, cb){
    this.push(JSON.stringify(obj));
    cb();
};

var data = "some data in here";
var rs = new stream.Readable({ objectMode: true });
rs.push(data);
rs.push(null);

rs.pipe(new StringifyStream())
  .pipe(gz)
  .pipe(fs.createWriteStream('test.gz'))
  .on('error', function(err){
    console.log("wtf error", err);
  })
  .on('finish', function(){
  console.log("write stream is done");
  // dosomething();
});

from here

import { createReadStream, createWriteStream } from 'fs'
import { createGzip } from 'zlib'
const filename = yourFile
// opens the file as a readable stream
createReadStream(filename)
   .pipe(createGzip())
   .pipe(createWriteStream(`${filename}.gz`))
   .on('finish', () => console.log('File is compressed'))

管道的顺序可能是问题所在。我可以通过让createGzipcreateWriteStream之前来解决这个问题。例如:

import Readable from "stream";
import zlib from "zlib";
import fs from "fs";
Readable.from([data])
   .pipe(zlib.createGzip())
   .pipe(fs.createWriteStream(`filePath.gzip`))
   .on("error", (error) => {
      // handle error
   })
   .on("finish", () => {
      // handle success
   })

最新更新