mongofiles仅支持单文件上传,不支持递归同步;推荐用python+pymongo+gridfs实现可控的全量同步,需处理路径拼接、哈希去重、元数据存储及异常文件过滤。

用 mongofiles 同步单个文件最简单,但不支持文件夹递归
直接跑 mongofiles put 只能传一个文件,比如 mongofiles --host localhost:27017 put report.pdf。想同步整个文件夹?它压根没提供 --recursive 或 -r 参数。硬套这个命令循环调用,还得自己处理路径、重名、元数据,容易漏文件或覆盖错。
实操建议:
- 别用
mongofiles做目录级同步——它定位就是调试/临时上传工具,不是同步器 - 如果只是偶尔传一两个文件,
mongofiles没问题;批量场景必须换方案 - 注意
mongofiles默认用fs这个数据库名和fs.files/fs.chunks集合,别和业务 GridFS 实例混了
Python + pymongo + gridfs 是最可控的全量同步方式
核心逻辑就三步:遍历本地路径 → 读取文件内容(或流式读)→ 调 GridFS.put() 存进去。关键在怎么处理文件名冲突、如何保留原始路径信息、要不要并发上传。
实操建议:
- 用
os.walk()或pathlib.Path.rglob("*")遍历,跳过子目录本身(只处理文件) -
GridFS.put()的filename参数建议拼上相对路径,比如data/images/logo.png,否则所有文件都挤在根目录下,查起来费劲 - 加
metadata字典存{"local_path": "/home/user/data/images/logo.png", "mtime": 1717023456},后续排查来源或去重用得上 - 大文件(>100MB)建议用
open(file, "rb")+gridfs.put(file_obj, ...)流式传,别一次性read()到内存
示例片段:
from gridfs import GridFS
from pymongo import MongoClient
client = MongoClient("mongodb://localhost:27017")
db = client["myapp"]
fs = GridFS(db)
with open("/path/to/file.txt", "rb") as f:
fs.put(f, filename="docs/file.txt", metadata={"source": "local_sync"})
同步前必须检查 _id 冲突和重复上传问题
GridFS 不会自动去重。同一 filename 多次 put(),会生成多条 fs.files 记录,fs.chunks 也跟着膨胀,磁盘白占,查询还变慢。
实操建议:
- 别依赖
filename唯一性——它只是普通字段,GridFS 不强制约束 - 同步脚本里先用
fs.find_one({"filename": "x/y/z.txt"})查是否存在;存在且metadata.mtime和本地一致,就跳过 - 更稳的做法是用文件内容哈希(如
sha256)当_id:传之前算哈希,fs.exists(_id=hash_hex),命中就不用再传 - 注意:
fs.exists()查_id比查filename快得多,因为_id有默认索引
忽略隐藏文件、临时文件和符号链接,避免同步失败或污染
像 .DS_Store、~$report.docx、.git/ 下的文件,或者指向不存在目标的符号链接,gridfs.put() 会报 OSError: [Errno 2] No such file or directory 或静默存入无效内容。
实操建议:
- 遍历时过滤掉以
.开头的文件名:if path.name.startswith("."):→continue - 跳过常见编辑器临时文件后缀:
if path.suffix in {".swp", ".swo", ".tmp", "~"}: - 对每个
path调用path.is_file()(不是is_dir()也不是is_symlink()),确保是真实可读文件 - Windows 下还要留意
desktop.ini,macOS 留意.localized,一并过滤
同步这事,最难的不是传过去,是传得干净、可追溯、不翻车。路径处理、去重逻辑、异常文件过滤,这三块漏一个,下次清理数据库就得手动翻 fs.files。










