GridFSUploadStream 必须用 write(ByteBuffer) 而非 write(byte[]),需 wrap 后 flip();上传需用固定缓冲区循环读 InputStream 并转 ByteBuffer;close() 返回 CompletableFuture 必须 join 或处理,否则文件不完整。

GridFSUploadStream 不能直接 write(byte[]),必须用 write(ByteBuffer)
Java Driver 的 GridFSUploadStream 是个异步写入通道,底层基于 Netty,不支持传统 IO 流的 write(byte[]) 方法。调用它会抛出 UnsupportedOperationException —— 这是新手最常卡住的第一步。
- 必须把原始字节转成
ByteBuffer:用ByteBuffer.wrap(bytes)或ByteBuffer.allocate()+put() - 写完后要调用
flip()(否则读位置为 0,实际无数据可写) - 每次
write()是非阻塞的,但需注意返回的CompletableFuture状态,尤其在流式上传中要链式 await 或 handle 异常
如何安全地把 InputStream 转成 GridFSUploadStream
不能用 inputStream.readAllBytes() 一次性加载到内存——大文件会 OOM;也不能用 inputStream.read(byte[]) 后直接 write,因为 GridFSUploadStream.write() 只认 ByteBuffer。
- 用固定大小缓冲区(如 8192 字节)循环读取
InputStream到byte[],再 wrap 成ByteBuffer并flip() - 每次
write()后建议检查isReady(),避免压入过多未 flush 的 buffer 导致背压溢出 - 务必在 finally 块或 try-with-resources 中调用
uploadStream.close(),否则文件元数据不写入fs.files集合,文件“消失”
上传时设置 metadata 和 contentType 的正确时机
GridFSUploadOptions 必须在调用 gridFSBucket.uploadFromStream() 时传入,**不能**在 GridFSUploadStream 创建后再改——它是个不可变配置对象。
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
-
contentType推荐显式设为"application/octet-stream"或根据文件扩展名推断(如"image/png"),否则默认为null,后续查询难过滤 -
metadata用new Document().append("user_id", 123).append("uploaded_at", new Date())即可,会存进fs.files.metadata - 如果需要分片大小控制(比如改默认 255KB),必须在
GridFSUploadOptions里设chunkSizeBytes(1024 * 1024),且该值必须 ≥ 1024
close() 不等于上传完成,要等 uploadStream.close() 返回的 CompletableFuture
调用 uploadStream.close() 只是触发关闭流程,它返回一个 CompletableFuture<objectid></objectid>。如果忽略这个 future,程序可能在文件还没写完时就退出,导致文件损坏或元数据缺失。
立即学习“Java免费学习笔记(深入)”;
- 简单场景下用
uploadStream.close().join()同步等待(注意会阻塞当前线程) - 异步服务中应
thenAccept(id -> log.info("Saved as {}", id))+exceptionally(e -> log.error("Upload failed", e)) - 别混淆
GridFSUploadStream和GridFSDownloadStream的生命周期:前者 close = 提交文件;后者 close = 释放连接,不涉及元数据写入
实际写法里最容易被跳过的是 flip() 和 close().join()。这两个点不处理,要么写不进去,要么以为写完了其实没落盘。


















