上传大文件到Dropbox时UploadSessionFinishAsync报错如何解决?
问题原因分析
- 分块上传逻辑重复提交首块数据:idx=0时,你已经通过
UploadSessionStartAsync上传了第一块内容,但是后续未跳过该块的append逻辑,会重复上传第一块,导致会话累计的上传字节数和cursor声明的偏移量不匹配,最终Finish时校验失败。 - 偏移量计算错误:当前cursor偏移量用
chunkSize * idx硬编码计算,没有使用实际读取的字节数累加,若实际读取的字节数不等于chunkSize(比如最后一块,或者文件流读取时的异常情况),会导致偏移量和实际上传量不符。 - 小文件上传逻辑存在隐式BUG:单块上传的分支中,你没有将文件流内容读取到
buffer中,直接使用空的buffer构造流上传,会导致小文件上传后为空。
修复方案
首先调整分块逻辑、偏移量计算方式,修复后的完整代码如下:
using (var stream = new MemoryStream(File.ReadAllBytes(fileName))) { var numChunks = (int)Math.Ceiling((double)stream.Length / chunkSize); var buffer = new byte[chunkSize]; string sessionId = null; ulong uploadedBytes = 0; // 用变量累计实际上传的字节数作为偏移量 if (numChunks == 1) { // 修复:先读文件内容到buffer var byteRead = stream.Read(buffer, 0, chunkSize); using (var memStream = new MemoryStream(buffer, 0, byteRead)) { Console.WriteLine($"Sending file: {path}"); var tst = await client.Files.UploadAsync(path, WriteMode.Overwrite.Instance, body: memStream); } } else { for (var idx = 0; idx < numChunks; idx++) { Console.WriteLine($"Uploading chunk {idx + 1} / {numChunks}."); var byteRead = stream.Read(buffer, 0, chunkSize); using (var memStream = new MemoryStream(buffer, 0, byteRead)) { if (idx == 0) { var result = await client.Files.UploadSessionStartAsync(body: memStream); sessionId = result.SessionId; uploadedBytes += (ulong)byteRead; // 首块已经通过Start上传,跳过后续append逻辑 continue; } var cursor = new UploadSessionCursor(sessionId, uploadedBytes); if (idx == numChunks - 1) { Console.WriteLine($"Finalizing file: {path}"); var response = await client.Files.UploadSessionFinishAsync(cursor, new CommitInfo(path), memStream); } else { await client.Files.UploadSessionAppendV2Async(cursor, body: memStream); uploadedBytes += (ulong)byteRead; } } } } var url = string.Empty; var link = await client.Sharing.ListSharedLinksAsync(path); if (link.Links.Count == 0) { var result = await client.Sharing.CreateSharedLinkWithSettingsAsync(path); url = result.Url; } else { url = link.Links[0].Url; } Console.WriteLine(); Console.WriteLine("Dropbox Download Link:"); Console.WriteLine(url); Console.WriteLine(); }
额外排查建议
如果修改后仍然报错,可以按以下步骤定位:
- 打印每个块的
byteRead、uploadedBytes数值,确认和实际文件大小匹配 - 捕获
UploadSessionFinishAsync抛出的异常详情,查看Dropbox返回的错误码,常见的invalid_cursor错误就对应偏移量不匹配的问题 - 确认
chunkSize取值符合Dropbox要求,分块上传的块大小最小为1MB,最大为150MB,推荐使用8MB作为默认分块大小
内容的提问来源于stack exchange,提问作者ErocM
相关产品推荐
相关产品推荐

