C#大文件上传方法 C#如何实现分片上传大文件

1次阅读

分片上传需前后端协同实现:前端按2–5mb切片并传fileid、chunkindex、totalchunks及哈希值;后端绕过iformfile,流式读取+幂等写入+分片校验+状态持久化+及时清理。

C#大文件上传方法 C#如何实现分片上传大文件

分片上传必须自己实现前后端协同

ASP.NET Core 默认的 IFormFile 无法处理 GB 级文件,服务端会直接拒绝或超时。分片不是加个配置就能开的开关,它要求前端按固定大小切片、携带序号和唯一标识(如 fileId),后端按序接收、暂存、校验,最后合并。跳过任一环节都会导致文件损坏或丢失。

  • 前端切片常用 File.slice()(浏览器)或 FileStream.Read() + 缓冲区(桌面端),单片建议 2–5 MB,太小增加 http 开销,太大降低失败重传效率
  • 每次请求必须带至少三个关键字段:fileId(整个文件唯一 ID)、chunkIndex(从 0 开始)、totalChunks
  • 后端不能依赖请求顺序——HTTP 不保证顺序到达,需用 fileId + chunkIndex 做幂等写入,重复上传同一片应忽略而非报错

后端接收分片要绕过模型绑定和默认限制

直接用 [FromForm]IFormFile 会触发 ASP.NET Core 的完整文件读取和内存缓冲,大文件直接 OOM。必须改用 Request.Body 流式读取,并手动解析 multipart boundary。

  • 禁用默认限制:在 Startup.csProgram.cs 中调用 ConfigureKestrel 设置 MaxRequestBodySize = long.MaxValue,同时在控制器上加 [RequestSizeLimit(long.MaxValue)]
  • 禁用模型绑定:方法签名不要含 IFormFile,改用 HttpRequest.Body + MultipartReader 解析,参考 microsoft.AspNetCore.WebUtilities.MultipartReader
  • 每片写入临时目录时,文件名建议为 {fileId}_{chunkIndex},避免并发写入冲突;不要用 MemoryStream 缓存整片内容

合并前必须做 MD5 或 SHA256 分片校验

网络传输中单片出错很常见,但用户往往只看到“上传完成”,实际文件已损坏。仅靠文件大小一致无法判断内容正确性。

  • 前端应在切片前计算整个文件的 fileHash,并随首片一起发送;每片上传时额外提交该片的 chunkHash
  • 后端保存每片时同步计算其哈希值,与前端传来的 chunkHash 比对,不一致则返回 400 Bad Request 并记录日志
  • 合并操作仅在所有片校验通过、且 chunkIndex 连续覆盖 0..totalChunks-1 后才执行,否则返回 409 Conflict

断点续传依赖服务端状态持久化

如果只把分片存在本地磁盘,iis 重启或 Kestrel 进程崩溃后,已上传的分片就丢了,用户只能重头来。真正的断点续传需要可恢复的状态记录。

  • 用轻量数据库(如 sqliteredis)存元数据:fileIdtotalChunksreceivedChunks(位图或集合)、status(uploading / merged / failed)
  • 前端发起上传前先发 HEAD /api/upload?fileId=xxx 查询已传片数,服务端返回 206 Partial Content 和已接收的 chunkIndex 列表
  • 合并完成后立即删临时分片文件,并将 status 改为 merged;失败时保留状态供重试,但需加 TTL 防止磁盘被占满

最易被忽略的是分片命名和清理时机——用时间戳或随机数作临时文件名,会导致无法关联同一文件的分片;合并成功后没删分片,几天下来磁盘就满了。这些细节不写进逻辑,系统迟早出问题。

text=ZqhQzanResources