前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊点Python:在Django中利用zipfile,StringIO等库生成下载的文件​

聊点Python:在Django中利用zipfile,StringIO等库生成下载的文件​

作者头像
用户8554325
发布2023-03-10 20:03:54
1.8K0
发布2023-03-10 20:03:54
举报
文章被收录于专栏:热度技术热度技术

最近在django中要用到文件下载的功能,通过查找,发现以下几种方式,就收集在一起,供日后方便查找。

第一种方式:创建一个临时文件。可以节省了大量的内存。当你有多个或两个用户并发时,你会发现节省内存是非常非常重要的。

你可以写入一个StringIO(from io import StringIO)对象。

代码语言:javascript
复制
>>> import zipfile
>>> import StringIO
>>> buffer= StringIO.StringIO()
>>> z= zipfile.ZipFile( buffer, "w" )
>>> z.write( "idletest" )
>>> z.close()
>>> len(buffer.getvalue())

第二种方式,将文件打包成一个文件,下载的方式,需要设置Content-Disposition

代码语言:javascript
复制
from django.http import HttpResponse
from wsgiref.util import FileWrapper

# generate the file
response = HttpResponse(FileWrapper(myfile.getvalue()), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response

当然,以上的方式对付小文件下载还是ok,因为都是读入到内存中,但如果某个文件特别大,就不能使用这种方式,那就应该采用另外一种方式,下面就是展示一下,在Django中的大文件下载如何写代码实现。如果文件非常大时,最简单的办法就是使用静态文件服务器,比如Apache或者Nginx服务器来处理下载。不过有时候,我们需要对用户的权限做一下限定,或者不想向用户暴露文件的真实地址,或者这个大内容是临时生成的(比如临时将多个文件合并而成的),这时就不能使用静态文件服务器了。

我们在django view中,需要用StreamingHttpResponse这两个类。完整的代码如下:

代码语言:javascript
复制
from django.http import StreamingHttpResponse
def big_file_download(request):
  # do something...
  def file_iterator(file_name, chunk_size=512):
    with open(file_name) as f:
      while True:
        c = f.read(chunk_size)
        if c:
          yield c
        else:
          break

  the_file_name = "big_file.pdf"
  response = StreamingHttpResponse(file_iterator(the_file_name))
  response['Content-Type'] = 'application/octet-stream'
  response['Content-Disposition'] = 'attachment;filename="{0}"'.format(the_file_name)
  return response

另外,给大家介绍一种使用zipstream库实现下载的功能,直接上代码,如下

代码语言:javascript
复制
class ZipUtilities(object):
    """
    打包文件成zip格式的工具类

    使用方式

    >>> utilities = ZipUtilities()
    >>> for file_obj in file_objs:
    >>>    tmp_dl_path = os.path.join(path_to, filename)
    >>> utilities.to_zip(tmp_dl_path, filename)
    >>> utilities.close()
    >>> response = StreamingHttpResponse(utilities.zip_file, content_type='application/zip')
    >>> response['Content-Disposition'] = 'attachment;filename="{0}"'.format("下载.zip")
    """
    zip_file = None

    def __init__(self):
        self.zip_file = zipstream.ZipFile(mode='w', compression=zipstream.ZIP_DEFLATED)

    def to_zip(self, file, name):
        if os.path.isfile(file):
            self.zip_file.write(file, arcname=os.path.basename(file))
        else:
            self.add_folder_to_zip(file, name)

    def add_folder_to_zip(self, folder, name):
        for file in os.listdir(folder):
            full_path = os.path.join(folder, file)
            if os.path.isfile(full_path):
                self.zip_file.write(full_path, arcname=os.path.join(name, os.path.basename(full_path)))
            elif os.path.isdir(full_path):
                self.add_folder_to_zip(full_path, os.path.join(name, os.path.basename(full_path)))

    def close(self):
        if self.zip_file:
            self.zip_file.close()
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 聊聊电商业务与技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档