Flask线程上传文件报错I/O operation on closed file 解决方案咨询
问题解决:Flask异步上传文件到S3报"I/O operation on closed file"错误
问题原因
Flask在请求处理完成(执行return后)会自动回收请求相关资源,包括上传文件的句柄。你把上传逻辑放到子线程后,主线程已经结束请求并关闭了文件,子线程启动时文件已无法读取,因此报错。
修改方案(无需本地存储大文件)
核心思路
将文件内容转存到内存缓冲区中,脱离请求生命周期的限制,让子线程可以安全访问文件内容;同时修正文件对象的获取方式(Flask上传文件需从request.files而非request.form读取)。
修改后的完整代码
from io import BytesIO from flask import request, redirect, url_for, login_required from werkzeug.utils import secure_filename import threading @application.route('/dashboard', methods=['POST']) @login_required def dashboard_post(): # 从request.files获取上传文件(原代码用request.form是错误的) file = request.files.get('input_file') if not file: # 可根据需求添加错误提示逻辑 return redirect(url_for('dashboard_upload')) # 将文件内容写入内存缓冲区 file_buffer = BytesIO() file.save(file_buffer) # 重置缓冲区指针到起始位置,确保后续读取完整内容 file_buffer.seek(0) filename = secure_filename(file.filename) # 启动子线程,传入内存缓冲区和文件名 worker_thread = threading.Thread(target=upload_file, args=[file_buffer, filename]) worker_thread.start() return redirect(url_for('dashboard_upload')) def upload_file(file_buffer, filename): try: S3_CLIENT.upload_fileobj( file_buffer, '<bucketname>', # 替换为你的实际存储桶名称 filename, ) print(f"文件 {filename} 已成功上传至S3") except Exception as e: print(f"S3上传失败: {str(e)}")
关键修改点说明
- 修正文件获取源:上传文件属于
multipart/form-data类型,必须从request.files中获取,原代码的request.form.get无法正确拿到文件对象。 - 内存缓冲区中转:用
BytesIO在内存中存储文件内容,脱离请求生命周期的限制,子线程可安全读取。 - 重置缓冲区指针:调用
file.save()后缓冲区指针会移至末尾,seek(0)确保upload_fileobj能从开头读取完整内容。
内容的提问来源于stack exchange,提问作者jfst
相关产品推荐
相关产品推荐

