杰瑞科技汇

Flask如何实现文件下载功能?

在 Flask 中实现文件下载功能

在 Flask 中实现文件下载功能可以通过多种方式实现,以下是几种常见的方法:

Flask如何实现文件下载功能?-图1
(图片来源网络,侵删)

使用 send_file 函数(推荐)

这是 Flask 提供的最简单、最直接的方法:

from flask import Flask, send_file
import os
app = Flask(__name__)
@app.route('/download/<filename>')
def download_file(filename):
    # 构建文件路径
    file_path = os.path.join('downloads', filename)
    # 检查文件是否存在
    if not os.path.exists(file_path):
        return "File not found", 404
    # 发送文件
    return send_file(
        file_path,
        as_attachment=True,  # 作为附件下载
        download_name=filename  # 设置下载时的文件名
    )
if __name__ == '__main__':
    app.run(debug=True)

使用 send_from_directory 函数

如果你有专门的下载目录,可以使用这个函数:

from flask import Flask, send_from_directory
import os
app = Flask(__name__)
@app.route('/download/<path:filename>')
def download_file(filename):
    directory = 'downloads'
    return send_from_directory(directory, filename, as_attachment=True)
if __name__ == '__main__':
    app.run(debug=True)

手动实现文件下载

如果你需要更多的控制,可以手动实现:

from flask import Flask, Response
import os
app = Flask(__name__)
@app.route('/download/<filename>')
def download_file(filename):
    file_path = os.path.join('downloads', filename)
    if not os.path.exists(file_path):
        return "File not found", 404
    def generate():
        with open(file_path, 'rb') as f:
            while True:
                chunk = f.read(8192)
                if not chunk:
                    break
                yield chunk
    return Response(
        generate(),
        mimetype='application/octet-stream',
        headers={
            'Content-Disposition': f'attachment; filename="{filename}"'
        }
    )
if __name__ == '__main__':
    app.run(debug=True)

高级用法

设置下载时的文件名

return send_file(
    file_path,
    as_attachment=True,
    download_name='new_name.pdf'  # 下载时显示的文件名
)

处理大文件流式下载

对于大文件,建议使用流式传输:

Flask如何实现文件下载功能?-图2
(图片来源网络,侵删)
from flask import Flask, Response
import os
app = Flask(__name__)
@app.route('/download/<filename>')
def download_large_file(filename):
    file_path = os.path.join('downloads', filename)
    if not os.path.exists(file_path):
        return "File not found", 404
    def generate():
        with open(file_path, 'rb') as f:
            while True:
                chunk = f.read(8192)  # 8KB chunks
                if not chunk:
                    break
                yield chunk
    return Response(
        generate(),
        mimetype='application/octet-stream',
        headers={
            'Content-Disposition': f'attachment; filename="{filename}"'
        }
    )

需要认证的文件下载

from flask import Flask, send_file, request, abort
from functools import wraps
app = Flask(__name__)
def auth_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            abort(401)
        return f(*args, **kwargs)
    return decorated
def check_auth(username, password):
    # 这里应该是实际的认证逻辑
    return username == 'admin' and password == 'secret'
@app.route('/download/<filename>')
@auth_required
def download_protected_file(filename):
    file_path = os.path.join('downloads', filename)
    if not os.path.exists(file_path):
        abort(404)
    return send_file(file_path, as_attachment=True)

注意事项

  1. 文件路径安全:确保用户提供的文件名不会导致路径遍历攻击,使用 os.path.joinos.path.abspath 来验证路径。

  2. 性能考虑:对于大文件,使用流式传输避免内存问题。

  3. MIME 类型:Flask 会尝试自动检测文件的 MIME 类型,但你可以手动指定:

    return send_file(file_path, mimetype='application/pdf')
  4. 缓存控制:可以添加缓存头控制浏览器行为:

    return send_file(
        file_path,
        as_attachment=True,
        cache_timeout=0  # 禁用缓存
    )

方法可以根据你的具体需求选择使用,send_file 是最常用和推荐的方式。

分享:
扫描分享到社交APP
上一篇
下一篇