gridfs 的 files.md5 已弃用,必须流式计算 sha-256 并存入 metadata.sha256;需建索引加速查询;下载后必须二次校验哈希并验证文件可用性。

GridFS 默认 MD5 已弃用,不能用于可靠校验
MongoDB 4.4+ 中 files.md5 字段已被官方标记为 deprecated,PyMongo 和 Node.js 驱动在 5.0+ 版本中也不再保证其生成逻辑一致。更关键的是:它只对拼接后的 chunk 整体计算一次,不反映原始文件内容;若上传时驱动版本不同、chunkSize 调整、或启用了压缩/加密,files.md5 就会失效。你看到的值可能是空、错位、或根本没写入——尤其在手动插入 fs.chunks 或绕过 GridFSBucket 的场景下。
必须自己流式计算 SHA-256 并存入 metadata
SHA-256 是当前推荐的完整性锚点,但不能依赖驱动自动生成。你得在上传前用流式方式计算,并显式塞进 metadata:
- Python(PyMongo):用
hashlib.sha256()分块读取(如每次read(8192)),避免File.read()导致 OOM - Node.js:用
fs.createReadStream()+crypto.createHash('sha256')管道更新,最后hash.digest('hex') - 上传时必须传入
metadata={'sha256': 'a1b2c3...'},不是写进files.md5,也不是存在自定义字段如sha256_hash - C#:用
SHA256.Create().ComputeHash(stream),结果转成小写无分隔符字符串(BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant())
查重和复用前,先建索引并精确查询
不做索引,db.fs.files.findOne({ "metadata.sha256": "..." }) 就是全表扫描,GB 级文件库一查就卡死:
- 在 MongoDB Shell 中执行:
db.fs.files.createIndex({"metadata.sha256": 1}) - 查询路径必须严格匹配:
"metadata.sha256",不能写成"sha256"、"metadata.sha256.value"或漏掉引号 - 返回非
null表示已存在,直接复用其_id(即file_id),跳过上传 - 如果上传后发现查不到,检查是否用了
disable_md5=True初始化桶——这个开关不影响你自定义的metadata写入
下载后仍需二次校验,不能只信上传时的哈希
即使上传前算的 SHA-256 和 metadata.sha256 完全一致,也不能代表文件“可用”:
- 下载时若某个
chunk丢失(如n: 5缺失),驱动默认跳过并继续拼接,最终文件变短,但files.length和metadata.sha256都不变 - 下载后必须重新流式计算 SHA-256,和
metadata.sha256比对——这步不能省,否则无法捕获读取阶段的损坏 - 比对前统一清洗:去掉所有非十六进制字符,转小写;不要直接用
==比较带空格或大写的官网哈希 - 真正安全的闭环是:上传前算一次 → 存入
metadata.sha256→ 下载后重算一次 → 二者一致 + 文件能被目标程序打开/解压/播放
metadata.sha256 只是一个快照,它不担保 chunk 能被完整读出、不担保 BSON 解析不出错、也不担保磁盘底层没位翻转。只要没在业务上下文里实际使用一次,就不能说文件“完整可用”。











