motor gridfs 读写必须用 async/await:上传需 async for 分块读取并 write,下载需 async for 流式获取,须 await close();chunk_size_bytes 应据文件大小、带宽和内存权衡设置。

Motor GridFS 读写必须用 async/await,不能混用同步写法
Motor 的 GridFSBucket 是纯异步接口,所有方法(如 open_upload_stream、open_download_stream)都返回协程对象,不是文件句柄。直接 file.write() 或 for chunk in file 会报 TypeError: 'coroutine' object is not iterable 或 AttributeError: 'coroutine' object has no attribute 'write'。
实操建议:
- 上传大文件时,用
async for遍历异步迭代器(如aiofiles.open(..., 'rb')),每次读一块(例如 64KB),再调用upload_stream.write(chunk) - 下载时,用
async for chunk in download_stream流式获取数据,别调download_stream.read()—— 它不支持,会报AttributeError - 务必在
async with或显式await upload_stream.close()后再结束上传,否则文件元数据不写入fs.files集合,后续查不到
上传时指定 chunk_size_bytes 要权衡网络延迟和内存占用
Motor 默认 chunk 大小是 255KB,但对千兆内网或 SSD 存储,可设为 1024 * 1024(1MB)提升吞吐;而上传大量小文件(如日志切片)时,设太大会浪费空间(每个 chunk 占用独立文档,MongoDB 文档上限 16MB)。
实操建议:
- 单文件 > 100MB:设
chunk_size_bytes=2097152(2MB),减少文档数量和 write 次数 - 带宽受限或内存紧张(如容器内存 chunk_size_bytes=65536(64KB),避免 await 期间堆积太多 chunk 缓存
- 不要设为
0或负数,Motor 会静默 fallback 到默认值,且不报错
下载流必须手动处理 Not found 异常,Motor 不抛 FileNotFoundError
Motor 的 open_download_stream 在文件不存在时,不会抛出 Python 原生异常,而是返回一个协程,await 后触发 motor.core.AgnosticGridFSBucket.NoFile 异常 —— 这个异常继承自 Exception,不是 OSError 子类,所以 except FileNotFoundError: 捕不到。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
实操建议:
- 下载前先用
await fsbucket.find_one({'filename': 'xxx'})做轻量检查(注意:这会多一次查询) - 更推荐直接 try/catch:
except motor.core.AgnosticGridFSBucket.NoFile:,并确保已from motor.core import AgnosticGridFSBucket - 如果用
file_id下载,错误类型一样,但异常信息里不带 filename,调试时容易懵
并发上传多个大文件时,别共用同一个 GridFSBucket 实例的上传流
GridFSBucket 实例本身是线程安全、可复用的,但每个 open_upload_stream 返回的流对象(AgnosticGridIn)**不可跨协程共享**。若在多个 asyncio task 中写入同一个流,会出现数据错乱、RuntimeError: cannot reuse already awaited coroutine,甚至 MongoDB 写入失败但无提示。
实操建议:
- 每个上传任务单独调用
await fsbucket.open_upload_stream(...),哪怕文件名相同 - 避免在 class 属性里缓存
self._upload_stream,它是一次性的 - 上传完成必须
await stream.close(),否则fs.chunks里残留未完成的 chunk 文档,影响后续清理
Motor 的 GridFS 流式操作没有“暂停/恢复”机制,断点续传得靠业务层记录已上传 chunk 数 + 自定义 metadata 查询,这个细节容易被忽略。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










