2009-06-14 17 views
5

के लिए ज़िप संग्रह बनाएं, एक वेब ऐप में मैं काम कर रहा हूं, उपयोगकर्ता फ़ाइलों से भरा फ़ोल्डर का ज़िप संग्रह बना सकता है। यहाँ यहाँ कोड है:तत्काल डाउनलोड

files = torrent[0].files 
    zipfile = z.ZipFile(zipname, 'w') 
    output = "" 

    for f in files: 
     zipfile.write(settings.PYRAT_TRANSMISSION_DOWNLOAD_DIR + "/" + f.name, f.name) 

downloadurl = settings.PYRAT_DOWNLOAD_BASE_URL + "/" + settings.PYRAT_ARCHIVE_DIR + "/" + filename 
output = "Download <a href=\"" + downloadurl + "\">" + torrent_name + "</a>" 
return HttpResponse(output) 

लेकिन यह एक लंबी प्रतीक्षा (10+ सेकंड) जबकि ज़िप संग्रह डाउनलोड किया जा रहा है बुरा पक्ष प्रभाव पड़ता है। क्या इसे छोड़ना संभव है? एक फ़ाइल में संग्रह को सहेजने के बजाय, क्या यह सीधे उपयोगकर्ता को भेजना संभव है?

मुझे लगता है कि टोरेंटफ्लक्स इस उत्कृष्ट सुविधा प्रदान करता है जिसके बारे में मैं बात कर रहा हूं। जीबी डेटा को ज़िप करने और इसे एक सेकंड के भीतर डाउनलोड करने में सक्षम होने के नाते।

उत्तर

2

आप एक धारा के उत्पादन के लिए अनुमति देने का उपयोग कर रहे जिप पुस्तकालय करता है। आप उपयोगकर्ता को स्ट्रीमिंग करते समय अस्थायी रूप से एक ज़िप फ़ाइल में लिखने के बजाय सीधे उपयोगकर्ता को स्ट्रीम कर सकते हैं।

+0

मैं इस किया जा सकता है कि वह क्या पूछ रहा है लगता है। – Travis

+0

यह फ़ाइल की तरह वस्तुओं की अनुमति देता है। एक फ़ाइल की तरह ऑब्जेक्ट हो सकता है जो buffered स्ट्रीम के रूप में कार्य करता है - मेरा जवाब देखें! –

5

यहां एक साधारण Django दृश्य फ़ंक्शन है जो /tmp में किसी भी पठनीय फ़ाइलों को ज़िपित करता है (ज़िप के रूप में) और ज़िप फ़ाइल देता है।

from django.http import HttpResponse 
import zipfile 
import os 
from cStringIO import StringIO # caveats for Python 3.0 apply 

def somezip(request): 
    file = StringIO() 
    zf = zipfile.ZipFile(file, mode='w', compression=zipfile.ZIP_DEFLATED) 
    for fn in os.listdir("/tmp"): 
     path = os.path.join("/tmp", fn) 
     if os.path.isfile(path): 
      try: 
       zf.write(path) 
      except IOError: 
       pass 
    zf.close() 
    response = HttpResponse(file.getvalue(), mimetype="application/zip") 
    response['Content-Disposition'] = 'attachment; filename=yourfiles.zip' 
    return response 

बेशक इस दृष्टिकोण केवल तभी कार्य करेगा ज़िप फ़ाइलें आसानी से स्मृति में फिट होगा - अगर नहीं, तो आप एक डिस्क फ़ाइल (जो आप से बचने के लिए कोशिश कर रहे हैं) का उपयोग करना होगा। उस स्थिति में, आप file = StringIO() को file = open('/path/to/yourfiles.zip', 'wb') के साथ प्रतिस्थापित करें और डिस्क फ़ाइल की सामग्री को पढ़ने के लिए file.getvalue() कोड के साथ प्रतिस्थापित करें।

0

एचटीपीआरस्पॉन्स (see docs) के निर्माता को एक इटरेटर पास करना संभव है। इससे आपको एक कस्टम इटरेटर बनाने की अनुमति मिल जाएगी जो डेटा को उत्पन्न करता है जैसा अनुरोध किया जा रहा है। हालांकि मुझे नहीं लगता कि एक ज़िप के साथ काम करेगा (आपको आंशिक ज़िप भेजना होगा क्योंकि यह बनाया जा रहा है)।

मुझे लगता है कि, एक अलग प्रक्रिया में, फ़ाइलों को ऑफलाइन बनाने का उचित तरीका होगा। उपयोगकर्ता तब प्रगति की निगरानी कर सकता है और उसके बाद फ़ाइल को डाउनलोड कर सकता है जब संभवतः ऊपर वर्णित इटरेटर विधि का उपयोग करके)। जब आप फ़ाइल अपलोड करते हैं और संसाधित होने की प्रतीक्षा करते हैं तो यह वही होगा जैसे यूट्यूब उपयोग की जाने वाली साइटें।

8

जैसा कि मन्द्रके कहते हैं, HttpResponse के निर्माता, अस्थिर वस्तुओं को स्वीकार करते हैं।

सौभाग्य से, ज़िप प्रारूप ऐसा है कि संग्रह एकल पास, केंद्रीय निर्देशिका रिकॉर्ड फ़ाइल के अंत में स्थित है में बनाया जा सकता है:

enter image description here

(Wikipedia से चित्र)

और सौभाग्य से, zipfile वास्तव में कोई भी खोज नहीं करता है जब तक आप केवल फाइलें जोड़ते हैं।

यहां कोड है जिसके साथ मैं आया था। कुछ नोट्स:

  • मैं जेपीईजी चित्रों का एक समूह ज़िप करने के लिए इस कोड का उपयोग कर रहा हूं। को संपीड़ित करने के लिए कोई बिंदु नहीं है, मैं केवल कंटेनर के रूप में ज़िप का उपयोग कर रहा हूं।
  • मेमोरी उपयोग ओ (size_of_largest_file) ओ नहीं है (size_of_archive)।और यह मेरे लिए काफी अच्छा है: संभावित रूप से विशाल संग्रह
  • यह कोड सामग्री-लंबाई शीर्षलेख सेट नहीं करता है, इसलिए उपयोगकर्ता को अच्छी प्रगति संकेत नहीं मिलता है। को पहले से गणना करने के लिए संभव होना चाहिए यदि सभी फ़ाइलों के आकार ज्ञात हैं।
  • ज़िप को सीधे इस तरह उपयोगकर्ता की सेवा करना मतलब है कि डाउनलोड पर फिर से शुरू नहीं होगा।

तो, यहाँ जाता है:

import zipfile 

class ZipBuffer(object): 
    """ A file-like object for zipfile.ZipFile to write into. """ 

    def __init__(self): 
     self.data = [] 
     self.pos = 0 

    def write(self, data): 
     self.data.append(data) 
     self.pos += len(data) 

    def tell(self): 
     # zipfile calls this so we need it 
     return self.pos 

    def flush(self): 
     # zipfile calls this so we need it 
     pass 

    def get_and_clear(self): 
     result = self.data 
     self.data = [] 
     return result 

def generate_zipped_stream(): 
    sink = ZipBuffer() 
    archive = zipfile.ZipFile(sink, "w") 
    for filename in ["file1.txt", "file2.txt"]: 
     archive.writestr(filename, "contents of file here") 
     for chunk in sink.get_and_clear(): 
      yield chunk 

    archive.close() 
    # close() generates some more data, so we yield that too 
    for chunk in sink.get_and_clear(): 
     yield chunk 

def my_django_view(request): 
    response = HttpResponse(generate_zipped_stream(), mimetype="application/zip") 
    response['Content-Disposition'] = 'attachment; filename=archive.zip' 
    return response 
संबंधित मुद्दे