切片上传需按索引命名并严格排序,前端传chunkindex和totalchunks,后端存为upload/{uploadid}/{chunkindex:04d},合并前校验索引连续性,用io.multireader流式合并确保原子性和数据干净。

上传切片时如何正确命名和排序文件
切片合并失败,八成是因为后端没按序拼接。前端上传的每个切片必须带唯一且可排序的索引,比如 filename_0001、filename_0002,不能依赖文件系统顺序或 HTTP 请求到达顺序。
推荐做法是让前端在上传时显式传入 chunkIndex(整数)和 totalChunks,后端用这两个值做校验和排序:
- 接收切片时,存为
upload/{uploadId}/{chunkIndex:04d},避免字符串自然排序出错(如10排在2前) - 合并前先检查是否存在从
0到totalChunks-1的全部索引,缺任一就直接返回错误"missing chunk at index X" - 不要用
filepath.Glob扫描目录来收集切片——结果无序且不可靠
用 io.MultiReader 合并切片比逐个 io.Copy 更安全
常见写法是开个 *os.File,循环 io.Copy 每个切片文件,但容易因中间某个切片读取失败导致目标文件残留脏数据,且无法回滚。
更稳妥的方式是用内存友好的流式合并:
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 把所有切片文件按索引顺序打开为
*os.File,构造成[]io.Reader - 传给
io.MultiReader得到一个单一io.Reader - 用
io.Copy一次性写入目标文件,失败则整个操作中断,目标文件保持干净 - 注意:切片文件需在
io.Copy完成后再统一Close(),否则可能触发 “file already closed” 错误
readers := make([]io.Reader, totalChunks) for i := 0; i <h3>完整性校验必须在合并后做,且用 <code>sha256.Sum256</code> 而非字符串比对</h3> <p>有人把每个切片的 hash 存下来,合并完再拼 hash,这是错的——SHA256 不具备可加性,拼接哈希值毫无意义。</p> <p>正确流程只有一条:合并完成后的完整文件,重新计算一次哈希,与前端传来的 <code>fileHash</code> 对比:</p>
- 前端必须在分片前就计算整个原始文件的
sha256.Sum256,Base64 编码后随首请求一起传上来 - 后端合并完成后,用
sha256.New()+io.Copy计算目标文件哈希,再用sum256.Equal()比较 - 别用
fmt.Sprintf("%x", sum)转字符串比较——大小写、补零不一致会导致误判 - 如果校验失败,立刻
os.Remove目标文件,避免脏文件残留
并发上传下如何避免切片覆盖或合并冲突
多个用户同时上传同名文件,或同一用户重试上传,都可能导致切片目录冲突。关键不是锁整个服务,而是隔离上传会话。
- 每个上传请求必须生成唯一
uploadId(推荐uuid.NewString()),所有切片路径都基于它 - 不要用用户 ID 或文件名做目录名——重名即覆盖
- 合并完成后,主动清理切片目录;失败时也应设超时自动清理(例如用
time.AfterFunc启动延迟删除) - 若需支持断点续传,得额外记录每个
uploadId的已收切片索引(可用 map[int]bool 存内存,或写入 Redis)
切片合并本身不复杂,真正容易翻车的是边界:索引错位、哈希误算、并发污染、残留文件。每一步都得假设上游不可信,自己守好校验和清理的底线。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










