Flask下載文件

前言

由于最近在做文件管理模塊的功能,所以難免會遇到文件上傳下載這塊的功能。不過文件上傳那塊是調(diào)用的OSS api,所以接觸的不多。

文件的下載:

1. 接口返回真實的文件

這種情況比較簡單, flask里帶有此類api, 可以用send_from_directory和send_file.

核心代碼如下:

from flask import send_file, send_from_directory
import os


@app.route("/download/<filename>", methods=['GET'])
def download_file(filename):
    # 需要知道2個參數(shù), 第1個參數(shù)是本地目錄的path, 第2個參數(shù)是文件名(帶擴展名)
    directory = os.getcwd()  # 假設(shè)在當(dāng)前目錄
    return send_from_directory(directory, filename, as_attachment=True)

后邊那個as_attachment參數(shù)需要賦值為True,不過此種辦法有個問題,就是當(dāng)filename里邊出現(xiàn)中文的時候,會報如下錯誤:

image.png

解決辦法:
使用flask自帶的make_response
代碼修改如下

from flask import send_file, send_from_directory
import os
from flask import make_response


@app.route("/download/<filename>", methods=['GET'])
def download_file(filename):
    # 需要知道2個參數(shù), 第1個參數(shù)是本地目錄的path, 第2個參數(shù)是文件名(帶擴展名)
    directory = os.getcwd()  # 假設(shè)在當(dāng)前目錄
    response = make_response(send_from_directory(directory, filename, as_attachment=True))
    response.headers["Content-Disposition"] = "attachment; filename={}".format(file_name.encode().decode('latin-1'))
    return response

使用make_response函數(shù)建立一個response對象,然后將filename編碼轉(zhuǎn)為latin-1,可以看到server.py里邊會嚴格按照latin-1編碼來解析filename,所以我這里的做法是先將utf8編碼的中文文件名默認轉(zhuǎn)為latin-1編碼。

2. 接口返回文件數(shù)據(jù)流

這種情況比較適合我現(xiàn)在的需求,因為我這邊是用requests庫,先請求一個oss鏈接,獲取到文件的數(shù)據(jù),然后我發(fā)現(xiàn)目前flask沒有這樣的api實現(xiàn),這里還是使用make_response方法實現(xiàn)。

代碼如下:

import mimetypes


@app.route('/fileManager/download/<projId>/<id>/<filename>', methods=['GET'])
def download_file(projId, id, filename):
    try:
        url = "your url"
        r = requests.get(url, timeout=500)
        if r.status_code != 200:
            raise Exception("Cannot connect with oss server or file is not existed")
        response = make_response(r.content)
        mime_type = mimetypes.guess_type(filename)[0]
        response.headers['Content-Type'] = mime_type
        response.headers['Content-Disposition'] = 'attachment; filename={}'.format(filename.encode().decode('latin-1'))
        return response
    except Exception as err:
        print('download_file error: {}'.format(str(err)))
        logging.exception(err)
        return Utils.beop_response_error(msg='Download oss files failed!')

解釋一下:
make_response很強大,下載一個文件,需要在response的headers里邊添加一些信息,比如文件的類型,文件的名字,是否以附件形式添加,這3個是比較關(guān)鍵的信息。
mime_type是文件的類型,我觀察send_file的源代碼發(fā)現(xiàn)里邊用到了mimetypes.guess_type()這個方法,也就是猜測文件的類型,然后這里我就直接搬過來用了哈哈,r.content其實就是文件的數(shù)據(jù)流,之前我是通過

with open(filename, 'wb') as file:
    file.write(r.content)

這樣實現(xiàn)下載文件到本地的,所以其實r.content是一個文件數(shù)據(jù)流,也不清楚我的名詞用的是否恰當(dāng)哈哈。

之所以不用第一種方式,是因為我本地生成文件了之后,需要刪除他,但是刪除的時候總是會提示該文件已經(jīng)被另一個程序使用,所以猜測是send_file這個api還在使用該文件,為了達到更好的效果,找到了第二種解決辦法。

其實還有一種解決辦法:

3. 發(fā)送靜態(tài)文件

其實原來和第一種差不多,調(diào)用的api不一樣,api是

from flask import app
import os


@app.route("/download/<filepath>", methods=['GET'])
def download_file(filepath):
    # 此處的filepath是文件的路徑,但是文件必須存儲在static文件夾下, 比如images\test.jpg
    return app.send_static_file(filepath)  

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,715評論 19 139
  • 22年12月更新:個人網(wǎng)站關(guān)停,如果仍舊對舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,447評論 22 257
  • [TOC]一直想做源碼閱讀這件事,總感覺難度太高時間太少,可望不可見。最近正好時間充裕,決定試試做一下,并記錄一下...
    何柯君閱讀 7,410評論 3 98
  • 快速啟動 是不是很渴望馬上開始?。窟@篇文檔將會很好的向你介紹Flask。假設(shè)你已經(jīng)安裝好了Flask。如果還沒有安...
    催眠_a363閱讀 801評論 0 1
  • Objective 你對今天學(xué)的記得什么? 1 生命的偉大秘密就是吸引力法則 2 吸引力法則說“同類相吸”,因此當(dāng)...
    楊麗靜奔跑的姑娘閱讀 277評論 1 1

友情鏈接更多精彩內(nèi)容