使用django進行大文件的上傳下載

 

下載

基於Django創建的網站,若是提供文件下載功能,最簡單的方式莫過於將靜態文件交給Nginx等處理,但有些時候,因爲網站自己邏輯,須要經過Django提供下載功能,如頁面數據導出功能(下載動態生成的文件)、先檢查用戶權限再下載文件等。所以,有必要研究一下文件下載功能在Django中的實現。python

最簡單的文件下載功能的實現

將文件流放入HttpResponse對象便可,如:django

def file_download(request):
  # do something...
  with open('file_name.txt') as f:
    c = f.read()
  return HttpResponse(c)

  

這種方式簡單粗暴,適合小文件的下載,但若是這個文件很是大,這種方式會佔用大量的內存,甚至致使服務器崩潰。瀏覽器

更合理的文件下載功能

Django的HttpResponse對象容許將迭代器做爲傳入參數,將上面代碼中的傳入參數c換成一個迭代器,即可以將上述下載功能優化爲對大小文件均適合;而Django更進一步,推薦使用 StreamingHttpResponse對象取代HttpResponse對象,StreamingHttpResponse對象用於將文件流發送給瀏覽器,與HttpResponse對象很是類似,對於文件下載功能,使用StreamingHttpResponse對象更合理。服務器

所以,更加合理的文件下載功能,應該先寫一個迭代器,用於處理文件,而後將這個迭代器做爲參數傳遞給StreaminghttpResponse對象,如:app

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 = "file_name.txt"
  response = StreamingHttpResponse(file_iterator(the_file_name))

  return response

  

文件下載功能再次優化

上述的代碼,已經完成了將服務器上的文件,經過文件流傳輸到瀏覽器,但文件流一般會以亂碼形式顯示到瀏覽器中,而非下載到硬盤上,所以,還要在作點優化,讓文件流寫入硬盤。優化很簡單,給StreamingHttpResponse對象的Content-Type和Content-Disposition字段賦下面的值便可,如:優化

response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;filename="test.pdf"'

  

完整代碼以下:網站

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
相關文章
相關標籤/搜索