动态创建zip并将其流式传输到客户端

los*_*ion 30 streaming zip node.js express

我正在使用NodeJs(w/express),我正在尝试将zip文件流回客户端.zip中包含的文件不在文件系统上,而是动态创建.我想将文件内容流式传输到zip并将zip流式传输回客户端.

IE我希望客户端收到:

tmp.zip
 --> 1.txt
 --> 2.txt
 --> 3.txt
Run Code Online (Sandbox Code Playgroud)

其中1,2,3.txt即时创建并流式传输到zip文件.这可能吗?

Cud*_*nny 51

Archiver有一个append方法,可以将文本另存为文件.要将该数据"流式传输"给用户,您只需将其传递给HTTP响应对象即可.

var Http = require('http');
var Archiver = require('archiver');

Http.createServer(function (request, response) {
    // Tell the browser that this is a zip file.
    response.writeHead(200, {
        'Content-Type': 'application/zip',
        'Content-disposition': 'attachment; filename=myFile.zip'
    });

    var zip = Archiver('zip');

    // Send the file to the page output.
    zip.pipe(response);

    // Create zip with some files. Two dynamic, one static. Put #2 in a sub folder.
    zip.append('Some text to go in file 1.', { name: '1.txt' })
        .append('Some text to go in file 2. I go in a folder!', { name: 'somefolder/2.txt' })
        .file('staticFiles/3.txt', { name: '3.txt' })
        .finalize();

}).listen(process.env.PORT);
Run Code Online (Sandbox Code Playgroud)

这将创建一个包含两个文本文件的zip文件.访问此页面的用户将看到文件下载提示.


sla*_*ava 6

解决方案:express.js,wait.for,zip-stream

app.get('/api/box/:box/:key/download', function (req, res) {

    var wait = require('wait.for');

    var items = wait.for(function (next) {
        BoxItem.find({box: req.Box}).exec(next)
    });

    res.set('Content-Type', 'application/zip');
    res.set('Content-Disposition', 'attachment; filename=' + req.Box.id + '.zip');

    var ZipStream = require('zip-stream');
    var zip = new ZipStream();

    zip.on('error', function (err) {
        throw err;
    });

    zip.pipe(res);

    items.forEach(function (item) {

        wait.for(function (next) {

            var path = storage.getItemPath(req.Box, item);
            var source = require('fs').createReadStream(path);

            zip.entry(source, { name: item.name }, next);
        })

    });

    zip.finalize();

});
Run Code Online (Sandbox Code Playgroud)


Dan*_*ohn 5

是的,有可能。我建议您看一下Streams Playground,以了解Node Streams的工作方式。

核心zlib库中的zip压缩似乎不支持多个文件。如果要使用tar-gzip,则可以使用node-tar对其进行压缩。但是,如果要使用ZIP,adm-zip似乎是最佳选择。另一种可能性是node-archiver

更新:

示例说明如何使用支持流的Archiver。只需fs.createReadStream用您正在动态创建的流代替,并将output流传递给Express的流,res而不是fs.createWriteStream

var fs = require('fs');

var archiver = require('archiver');

var output = fs.createWriteStream(__dirname + '/example-output.zip');
var archive = archiver('zip');

output.on('close', function() {
  console.log('archiver has been finalized and the output file descriptor has closed.');
});

archive.on('error', function(err) {
  throw err;
});

archive.pipe(output);

var file1 = __dirname + '/fixtures/file1.txt';
var file2 = __dirname + '/fixtures/file2.txt';

archive
  .append(fs.createReadStream(file1), { name: 'file1.txt' })
  .append(fs.createReadStream(file2), { name: 'file2.txt' });

archive.finalize(function(err, bytes) {
  if (err) {
    throw err;
  }

  console.log(bytes + ' total bytes');
});
Run Code Online (Sandbox Code Playgroud)