Flask下載文件

前言

因爲最近在作文件管理模塊的功能,因此不免會遇到文件上傳下載這塊的功能。不過文件上傳那塊是調用的OSS api,因此接觸的很少。python

文件的下載:

1. 接口返回真實的文件

這種狀況比較簡單, flask裏帶有此類api, 能夠用send_from_directory和send_file.flask

核心代碼以下:api

from flask import send_file, send_from_directory
import os


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

後邊那個as_attachment參數須要賦值爲True,不過此種辦法有個問題,就是當filename裏邊出現中文的時候,會報以下錯誤:app

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個參數, 第1個參數是本地目錄的path, 第2個參數是文件名(帶擴展名)
    directory = os.getcwd()  # 假設在當前目錄
    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函數創建一個response對象,而後將filename編碼轉爲latin-1,能夠看到server.py裏邊會嚴格按照latin-1編碼來解析filename,因此我這裏的作法是先將utf8編碼的中文文件名默認轉爲latin-1編碼。編碼

2. 接口返回文件數據流

這種狀況比較適合我如今的需求,由於我這邊是用requests庫,先請求一個oss連接,獲取到文件的數據,而後我發現目前flask沒有這樣的api實現,這裏仍是使用make_response方法實現。url

代碼以下:code

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個是比較關鍵的信息。
mime_type是文件的類型,我觀察send_file的源代碼發現裏邊用到了mimetypes.guess_type()這個方法,也就是猜想文件的類型,而後這裏我就直接搬過來用了哈哈,r.content其實就是文件的數據流,以前我是經過orm

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

這樣實現下載文件到本地的,因此其實r.content是一個文件數據流,也不清楚個人名詞用的是否恰當哈哈。server

之因此不用第一種方式,是由於我本地生成文件了以後,須要刪除他,可是刪除的時候老是會提示該文件已經被另外一個程序使用,因此猜想是send_file這個api還在使用該文件,爲了達到更好的效果,找到了第二種解決辦法。

其實還有一種解決辦法:

3. 發送靜態文件

其實原來和第一種差很少,調用的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)
相關文章
相關標籤/搜索