You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Flask服务直接上传文件至Minio Bucket(无需本地暂存)

直接从Flask上传文件到MinIO(无需本地存储)

当然可以实现直接上传!你完全不需要先把文件存到本地——Flask的FileStorage对象本身就支持类文件对象的接口,直接就能传给MinIO的put_object方法,既省掉本地存储的步骤,又能提升上传效率、节省磁盘空间。

修改思路

  1. 移除本地文件保存的冗余代码(file.save(...))
  2. 直接使用Flask上传的FileStorage对象的流(file.stream)作为MinIO的数据源
  3. 正确获取文件大小(MinIO的put_object必须传入文件长度参数)
  4. 调整upload_object函数,让它接收文件流和大小,而非本地文件路径

修改后的完整代码

from flask import Flask, request, flash
from werkzeug.utils import secure_filename
from minio import Minio
from minio.error import ResponseError
import os

# 初始化MinIO客户端(请替换成你的MinIO服务配置)
minioClient = Minio(
    'your-minio-server:9000',
    access_key='your-access-key',
    secret_key='your-secret-key',
    secure=False  # 根据你的MinIO是否启用HTTPS调整
)

ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', '7z', 'iso'}
app = Flask(__name__)

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def upload_object(object_name, file_obj, file_size):
    try:
        # 直接通过文件流上传到MinIO
        result = minioClient.put_object(
            'miniotestbucket', 
            object_name, 
            file_obj, 
            file_size
        )
        print(f"文件 {object_name} 上传成功,ETag: {result.etag}")
        return True
    except ResponseError as e:
        print(f"MinIO响应错误: {e}")
        return False
    except Exception as e:
        print(f"上传失败: {e}")
        return False

@app.route('/', methods=['GET','POST'])
def upload_file():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('No file part')
            return '未检测到上传文件'
        file = request.files['file']
        if file.filename == '':
            flash('No selected file')
            return '错误:未选择文件'
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            
            # 获取文件大小:优先用content_length,不可靠时手动计算
            if file.content_length:
                file_size = file.content_length
            else:
                # 移动指针到文件末尾获取大小,再重置回开头(否则MinIO会读取空内容)
                file.seek(0, os.SEEK_END)
                file_size = file.tell()
                file.seek(0)
            
            # 直接上传到MinIO,无需本地存储
            upload_success = upload_object(filename, file.stream, file_size)
            if upload_success:
                return '文件已成功存储到MinIO Bucket!'
            else:
                return '上传到MinIO失败,请检查服务配置'
    return '''
    <!doctype html>
    <title>Upload IPS File</title>
    <h1>Upload IPS File</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''

if __name__ == '__main__':
    app.run(debug=True)

关键细节说明

  • 文件流的直接使用:Flask的request.files['file']是FileStorage实例,它的stream属性是标准的类文件对象,完全满足MinIOput_object对数据源的要求。
  • 文件大小的兼容性处理:file.content_length可能会因为客户端上传时未携带该字段而返回None,所以我们添加了手动计算的兜底方案——通过seek和tell获取文件真实大小,之后必须把指针重置回开头,否则MinIO会从文件末尾开始读取,导致上传空文件。
  • 移除本地存储依赖:现在不需要UPLOAD_FOLDER配置和本地文件保存的步骤,直接跳过即可,减少了代码复杂度和磁盘IO操作。

内容的提问来源于stack exchange,提问作者csymvoul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 14:42:32