2013-11-20 12 views
18

NodeJs(w/express)を使用しています。クライアントにzipファイルをストリーミングしようとしています。 zipに含まれるファイルは、ファイルシステム上には存在せず、動的に作成されます。ファイルの内容をzipにストリームし、zipをクライアントにストリームしたいと思います。クライアントにジップを動的に作成してストリームします。

I.E.

1,2,3.txtはその場で作成され、zipファイルにストリーミングされます。これは可能ですか?

+0

は... HTTPクライアントがどのようなファイルを受信ん最終的には? zipファイル?または3つのテキストファイルの連結? –

+0

申し訳ありませんが、書式設定がうまくいけば、より明確です。私はジップを送り返したい。 2つの主な問題私は頭を抱えようとしています。 1.ジップをストリーミングする方法、2.私の3つのファイルを、私がストリーミングしているZIPファイルにストリーミングする方法。 I.ファイルシステム上に既に存在するファイルのzipをストリーミングする例を見てきましたが、その場でファイルを作成している場合はこれを行う方法の例はありません。 – lostintranslation

+0

あなたは同じ回避策を見つけることができましたか? –

答えて

31

には、テキストをファイルとして保存できる追加メソッドがあります。そのデータをユーザーに「ストリーム」するには、単に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); 

これにより、2つのテキストファイルを含むzipファイルが作成されます。このページにアクセスしたユーザーには、ファイルダウンロードのプロンプトが表示されます。

+0

今、すべてのファイルを追加した後に作成されたzipファイルはどうなりますか?同じような状況があり、ユーザーが複数のファイルを一度にダウンロードできるようにしたい。私は応答と一緒にそれらを送ることができないので。私は、一時的なジップを作成し、そこにファイルを移動し、それを提供し、スペースを保存するためにそれを削除する必要があります。では、アーカイバは一時的なzipファイルまたは永続的なzipファイルを作成しますか? – DeadMan

+1

私は、zipファイルが構築されているので、http要求に対する応答であるストリームにこれらのビットを書き込んでいるという点で、zipファイルが「作成」されているとは限りません。私は、ファイルがブラウザに送信され、それが保存されるまでエンドユーザーの一時ファイルに保存されるまで、何分かの間RAM上に存在することを確信しています(または、それがかなり大きい場合はファイルをスワップします)。場所。私はこのコードを数ヶ月間稼動させていましたが、ディスクスペースの使用量は変わらず、パージする必要がある一時的なzipはありません。 – CuddleBunny

+1

アーカイバレポのこの例は私を助けました。 https://github.com/ctalkington/node-archiver/blob/master/examples/express.js – eephillip

3

はい、可能です。ノードストリームの仕組みを理解するには、Streams Playgroundをお勧めします。

コアzlibライブラリのzip圧縮は、複数のファイルをサポートしていないようです。 tar-gzipを使いたい場合はnode-tarでタールすることができます。しかし、あなたがZIPを望むなら、adm-zipは最良の選択肢のように見えます。別の可能性はnode-archiverです。

更新:

このexampleストリームをサポートアーカイバを使用する方法を示しています。 fs.createReadStreamを動的に作成するストリームに置き換えて、fs.createWriteStreamではなくoutputストリームをExpressのresに置き換えてください。

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'); 
}); 
+0

混乱している部分私は、ファイルシステム上のファイルではなく、ストリームにzipを書き込むためにadm-zip(または他のzipモジュール)を使用する方法がわかりません。ストリームファイルをzipにストリームすることはもちろん、クライアントにストリーミングすることもできます。 – lostintranslation

+0

私はあなたのための例を追加しました。その例を見た – dankohn

+0

。それでも私は仕事が必要なものを手に入れることはできません。私はその場でfile1とfile2を作成しています(ファイルシステムにはありません)。これらのファイルのデータを作成するときに、ストリームに追加する必要があります。しかし、私はそれを追加するようにそれを圧縮したい。 – lostintranslation

5

とソリューション:それはあなたが「zipファイルにストリーム」によって何を意味するかは明らかではありませんexpress.js、wait.for、ジップストリーム

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

}); 
+0

@ ZachBモジュールがキャッシュされるので、遅くなるとは思わない。 –

関連する問題