سؤال

في تطبيق ويب أعمل عليه، يمكن للمستخدم إنشاء أرشيف مضغوط لمجلد مليء بالملفات. هنا هنا الرمز:

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+ ثانية) بينما يتم تنزيل أرشيف الرمز البريدي. هل من الممكن تخطي هذا؟ بدلا من حفظ الأرشيف إلى ملف، هل من الممكن إرساله مباشرة إلى المستخدم؟

أعتقد أن Torrentflux يوفر ميزة Excat هذه التي أتحدث عنها. القدرة على الدفع GBS من البيانات وتنزيلها في غضون ثانية.

هل كانت مفيدة؟

نصائح أخرى

كما يقول ماندريك، يقبل منشئ httpresponse الأشياء القريبة.

لحسن الحظ، فإن تنسيق الرمز البريدي هو مثل هذا الأرشيف يمكن إنشاؤه في تمريرة واحدة، ويقع سجل الدليل المركزي في نهاية الملف:

enter image description here

(صورة من ويكيبيديا)

ولحسن الحظ، zipfile في الواقع لا يقوم بأي تسعى طالما قمت بإضافة ملفات فقط.

هنا هو الرمز الذي توصلت إليه. بعض الملاحظات:

  • أنا أستخدم هذا الرمز لتخفيض مجموعة من الصور JPEG. ليس هناك نقطة ضغط لهم، أنا أستخدم الرمز البريدي فقط كحاوية.
  • استخدام الذاكرة هو O (size_of_largest_file) وليس O (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

إليك وظيفة عرض DJANGO بسيطة تصل إلى أي ملفات مقروءة (كمثال) /tmp وإرجاع ملف zip.

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

بالطبع سوف يعمل هذا النهج فقط إذا كانت ملفات ZIP سوف تتناسب بسهولة في الذاكرة - إذا لم يكن كذلك، فسيتعين عليك استخدام ملف قرص (الذي تحاول تجنبه). في هذه الحالة، أنت فقط استبدال file = StringIO() مع file = open('/path/to/yourfiles.zip', 'wb') واستبدال ذلك file.getvalue() مع رمز لقراءة محتويات ملف القرص.

هل تتسم مكتبة الرمز البريدي في استخدام الإخراج إلى دفق. يمكنك الدخول مباشرة إلى المستخدم بدلا من الكتابة مؤقتا إلى ملف مضغوط ثم تدفق المستخدم.

من الممكن اجتياز مقاومة للماء في منشئ HTTPRESPONSE (انظر المستندات). وبعد من شأنه أن يسمح لك بإنشاء جهاز كمتدرج مخصص ينشئ بيانات كما يتم طلبه. ومع ذلك، لا أعتقد أن ذلك سيعمل مع الرمز البريدي (سيكون عليك إرسال الرمز البريدي الجزئي لأنه يتم إنشاؤه).

الطريقة الصحيحة، أعتقد أن إنشاء الملفات دون اتصال بالإنترنت، في عملية منفصلة. يمكن للمستخدم بعد ذلك مراقبة التقدم المحرز ثم قم بتنزيل الملف عند استعداده (ربما باستخدام طريقة ITERATOR الموضحة أعلاه). سيكون هذا مماثلة ما هي المواقع مثل استخدام YouTube عند تحميل ملف وانتظر معالجةها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top