2013-11-20 6 views
18

पर गतिशील रूप से ज़िप बनाएं और स्ट्रीम करें मैं नोडजेज़ (डब्ल्यू/एक्सप्रेस) का उपयोग कर रहा हूं और मैं क्लाइंट को एक ज़िप फ़ाइल स्ट्रीम करने की कोशिश कर रहा हूं। ज़िप में निहित फाइलें फ़ाइल सिस्टम पर नहीं रहती हैं, बल्कि वे गतिशील रूप से बनाई जाती हैं। मैं ज़िप पर फ़ाइल (ओं) सामग्री स्ट्रीम करना चाहता हूं और ज़िप को क्लाइंट को वापस स्ट्रीम करना चाहता हूं।क्लाइंट

आईई। मैं ग्राहक को प्राप्त करना चाहता हूं:

tmp.zip 
--> 1.txt 
--> 2.txt 
--> 3.txt 

जहां फ्लाई पर 1,2,3.txt बनाए जाते हैं और ज़िप फ़ाइल में स्ट्रीम किए जाते हैं। क्या यह संभव है?

+0

यह स्पष्ट नहीं कर रहा है आप से क्या मतलब है "ज़िप फ़ाइल स्ट्रीम" ... क्या फ़ाइल HTTP ग्राहक प्राप्त करता है अंततः? ज़िप फ़ाइल? या तीन पाठ फ़ाइलों का एक संयोजन? –

+0

क्षमा करें, स्वरूपण गड़बड़ हो गया था, उम्मीद है कि यह अधिक स्पष्ट है। मैं एक ज़िप वापस भेजना चाहता हूँ। 2 मुख्य मुद्दे मैं अपने सिर को चारों ओर लपेटने की कोशिश कर रहा हूं। 1. ज़िप को वापस कैसे स्ट्रीम करें, 2. मेरी 3 फाइलों को एक ज़िप फ़ाइल में कैसे स्ट्रीम करें जिसे मैं वापस स्ट्रीम कर रहा हूं। अर्थात। मैंने फ़ाइलों के एक ज़िप को स्ट्रीम करने के उदाहरण देखे हैं जो पहले से ही फाइल सिस्टम पर मौजूद हैं, लेकिन अगर आप फ्लाई में फाइलें बना रहे हैं तो इसका कोई उदाहरण नहीं है। – lostintranslation

+0

क्या आप इसके लिए कोई काम नहीं ढूंढ पाए? –

उत्तर

31

Archiver में एक संलग्न विधि है जो आपको फ़ाइल को फ़ाइल के रूप में सहेजने देती है। उपयोगकर्ता को उस डेटा को "स्ट्रीम" करने के लिए आप बस 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); 

यह दो टेक्स्ट फ़ाइलों के साथ एक ज़िप फ़ाइल बनाएगा। इस पृष्ठ पर आने वाले उपयोगकर्ता को फ़ाइल डाउनलोड प्रॉम्प्ट के साथ प्रस्तुत किया जाएगा। साथ

+0

अब सभी फ़ाइलों को जोड़ने के बाद बनाई गई ज़िप फ़ाइल का क्या होता है। मेरे पास एक समान स्थिति है, जहां मैं अपने उपयोगकर्ता को एक साथ कई फाइलें डाउनलोड करने की अनुमति देना चाहता हूं। चूंकि मैं उन्हें प्रतिक्रिया के साथ एक साथ नहीं भेज सकता।मुझे एक अस्थायी ज़िप बनाना है और इसमें फ़ाइलों को स्थानांतरित करना है और फिर इसे सेवा देना है और फिर इसे स्थानांतरित करने के लिए इसे हटा देना है। तो, क्या संग्रहकर्ता अस्थायी ज़िप फ़ाइल या स्थायी बनाता है? – DeadMan

+1

मुझे नहीं लगता कि ज़िप फ़ाइल प्रति "निर्मित" है, क्योंकि उपयोगिता ज़िप फ़ाइल का निर्माण कर रही है, यह स्ट्रीम में उन बिट्स को लिख रही है जो http अनुरोध की प्रतिक्रिया होगी। मुझे यकीन है कि यह रैम में कहीं भी रहता है (या फ़ाइल को स्वैप कर देता है) एक मिनट के लिए जब तक कि ब्राउज़र को ब्राउज़र में नहीं भेजा जाता है, तब तक इसे अंतिम उपयोगकर्ता की अस्थायी फ़ाइलों तक सहेजने तक सहेजा जाएगा एक स्थल। मेरे पास यह कोड कुछ महीनों के लिए लाइव चल रहा है और मेरा डिस्क स्पेस उपयोग वही बना रहा है, इसलिए कोई अस्थायी ज़िप नहीं है जिसे आपको शुद्ध करने की आवश्यकता है। – CuddleBunny

+1

आर्किवर रेपो से इस उदाहरण ने मेरी मदद की। https://github.com/ctalkington/node-archiver/blob/master/examples/express.js – eephillip

3

हां, यह संभव है। मैं नोड स्ट्रीम कैसे काम करता है इसके बारे में महसूस करने के लिए Streams Playground पर एक नज़र डालने की सलाह देते हैं।

कोर zlib लाइब्रेरी में ज़िप संपीड़न एकाधिक फ़ाइलों का समर्थन नहीं करता है। यदि आप टैर-जीज़िप के साथ जाना चाहते हैं, तो आप इसे node-tar से टैर कर सकते हैं। लेकिन अगर आप ज़िप चाहते हैं, adm-zip सबसे अच्छा विकल्प की तरह दिखता है। एक और संभावना node-archiver है।

अद्यतन:

यह example से पता चलता Archiver, जो धाराओं का समर्थन करता है का उपयोग कैसे करें। fs.createReadStream को उन गतियों के साथ प्रतिस्थापित करें जिन्हें आप गतिशील रूप से बना रहे हैं, औरके बजाय पर output स्ट्रीम करें।

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

भ्रमित भाग यह है कि मुझे कोई जानकारी नहीं है कि ज़िप को लिखने के लिए एडम-ज़िप (या कोई अन्य ज़िप मॉड्यूल) का उपयोग कैसे करें, फाइल सिस्टम पर फ़ाइल नहीं। ज़िप पर स्ट्रीम फ़ाइल का उल्लेख नहीं करना है जो क्लाइंट पर स्ट्रीमिंग कर रहा है। – lostintranslation

+0

मैंने आपके लिए एक उदाहरण जोड़ा। – dankohn

+0

उस उदाहरण को देखा। अभी भी मुझे काम करने की ज़रूरत नहीं है। मैं फ्लाई पर फ़ाइल 1 और फ़ाइल 2 बना रहा हूं (वे फाइल सिस्टम पर नहीं हैं)। जैसे ही मैं उन फ़ाइलों के लिए डेटा बनाता हूं, मैं इसे स्ट्रीम में जोड़ना चाहता हूं। लेकिन मैं इसे जोड़ना चाहता हूं क्योंकि मैं इसे जोड़ता हूं। – lostintranslation

5

समाधान: 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 मुझे नहीं लगता कि यह धीमा है क्योंकि मॉड्यूल कैश हो जाते हैं। –