VB.NET(.NET Framework4.6.2)实现Dropbox上传的暂停/恢复/停止
实现Dropbox分片上传的暂停/恢复/停止功能
针对你的VB.NET + .NET Framework 4.6.2场景,我会基于你现有的分片上传代码,添加完整的暂停/恢复/停止逻辑。核心思路是用状态类保存上传进度、用信号量控制暂停、用取消令牌实现停止,同时优化原代码的内存使用(避免一次性加载整个文件到内存)。
第一步:创建上传状态类
首先定义一个类来保存暂停/恢复需要的关键信息,甚至可以序列化到本地实现跨会话恢复:
Imports System.IO Public Class DropboxUploadState ' Dropbox授权信息 Public Property AccessToken As String ' 本地文件路径 Public Property LocalFilePath As String ' Dropbox目标文件夹 Public Property TargetFolder As String ' 上传会话ID(Dropbox用于识别分片会话) Public Property SessionId As String ' 已上传的分片数 Public Property UploadedChunks As Integer ' 总分片数 Public Property TotalChunks As Integer ' 文件总大小 Public Property FileSize As Long ' 分片大小(保持你原来的1MB) Public Property ChunkSize As Integer = 1024 * 1024 End Class
第二步:修改分片上传函数(支持控制)
重写你的ChunkUpload函数,加入暂停/停止控制逻辑,同时改用FileStream逐片读取文件(更省内存):
Imports Dropbox.Api Imports Dropbox.Api.Files Imports System.Threading Public Async Function ChunkUploadWithControl(ByVal uploadState As DropboxUploadState, progressBar As ToolStripProgressBar, ct As CancellationToken, pauseEvent As ManualResetEventSlim) As Task Dim config = New DropboxClientConfig("Project.vb") Dim client = New DropboxClient(uploadState.AccessToken, config) Dim localFileName = Path.GetFileName(uploadState.LocalFilePath) ' 确保Dropbox路径用斜杠分隔 Dim targetPath = Path.Combine(uploadState.TargetFolder, localFileName).Replace("\", "/") Using fs As New FileStream(uploadState.LocalFilePath, FileMode.Open, FileAccess.Read) ' 初始化或恢复会话 If String.IsNullOrEmpty(uploadState.SessionId) Then ' 第一次上传:创建新会话 Dim firstChunkBuffer(uploadState.ChunkSize - 1) As Byte Dim bytesRead = fs.Read(firstChunkBuffer, 0, uploadState.ChunkSize) Using memStream As New MemoryStream(firstChunkBuffer, 0, bytesRead) Dim result = Await client.Files.UploadSessionStartAsync(body:=memStream, cancellationToken:=ct) uploadState.SessionId = result.SessionId uploadState.UploadedChunks = 1 End Using Else ' 恢复上传:定位到已完成的分片位置 fs.Seek(uploadState.UploadedChunks * uploadState.ChunkSize, SeekOrigin.Begin) End If ' 计算总分片数并初始化进度条 uploadState.TotalChunks = CInt(Math.Ceiling(fs.Length / CDbl(uploadState.ChunkSize))) UpdateProgressBar(progressBar, uploadState.UploadedChunks, uploadState.TotalChunks) ' 循环上传剩余分片 Do While uploadState.UploadedChunks < uploadState.TotalChunks ' 检查是否需要暂停:如果暂停,这里会阻塞直到恢复或停止 pauseEvent.Wait(ct) ' 检查是否收到停止指令 ct.ThrowIfCancellationRequested() ' 读取当前分片数据 Dim buffer(uploadState.ChunkSize - 1) As Byte Dim bytesRead = fs.Read(buffer, 0, uploadState.ChunkSize) Using memStream As New MemoryStream(buffer, 0, bytesRead) Dim cursor As New UploadSessionCursor(uploadState.SessionId, CUInt(uploadState.UploadedChunks * uploadState.ChunkSize)) If uploadState.UploadedChunks = uploadState.TotalChunks - 1 Then ' 最后一个分片:完成上传 Dim commitInfo As New CommitInfo(targetPath, WriteMode.Overwrite.Instance, False, Nothing, False) Await client.Files.UploadSessionFinishAsync(cursor, commitInfo, memStream, cancellationToken:=ct) Else ' 中间分片:追加到会话 Await client.Files.UploadSessionAppendV2Async(cursor, body:=memStream, cancellationToken:=ct) End If End Using ' 更新已上传分片数和进度 uploadState.UploadedChunks += 1 UpdateProgressBar(progressBar, uploadState.UploadedChunks, uploadState.TotalChunks) Loop ' 上传完成后重置进度条 UpdateProgressBar(progressBar, 0, 100) End Using End Function ' 安全更新UI进度条(避免跨线程问题) Private Sub UpdateProgressBar(progressBar As ToolStripProgressBar, current As Integer, total As Integer) progressBar.Invoke(Sub() progressBar.Maximum = total progressBar.Value = current progressBar.ToolTipText = $"{CInt((current / total) * 100)}%" End Sub) End Sub
第三步:在窗体中添加控制逻辑
在你的窗体类中添加成员变量,然后实现暂停/恢复/停止按钮的事件:
Imports System.IO Imports System.Threading Public Class YourForm ' 取消令牌:用于停止上传 Private _cts As CancellationTokenSource ' 上传状态:保存进度信息 Private _uploadState As DropboxUploadState ' 暂停信号量:控制上传的暂停/恢复 Private _pauseEvent As ManualResetEventSlim = New ManualResetEventSlim(True) ' 默认不暂停 ' 原有的上传按钮点击事件修改 Private Async Sub DropboxToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles DropboxToolStripMenuItem.Click If _cts IsNot Nothing AndAlso Not _cts.Token.IsCancellationRequested Then MessageBox.Show("已有上传任务在进行中!") Return End If Dim newBakFile As String = $"MYFILE.EXT{Date.Today.ToShortDateString}" Try If ToolStripProgressBar1.Value <> 100 Then ' 复制备份文件 Try File.Copy("ThisDB.accdb", newBakFile, True) Catch ex As IOException MessageBox.Show($"复制文件失败:{ex.Message}") Return End Try ' 初始化UI状态 ToolStripProgressBar1.Visible = True BackupToolStripMenuItem.Enabled = False DropboxToolStripMenuItem.Enabled = False ' 初始化上传状态 _uploadState = New DropboxUploadState With { .AccessToken = My.Settings.AccessToken, .LocalFilePath = newBakFile, .TargetFolder = "/Tests", .SessionId = String.Empty, .UploadedChunks = 0, .FileSize = New FileInfo(newBakFile).Length } ' 初始化取消令牌 _cts = New CancellationTokenSource() _pauseEvent.Set() ' 确保初始为运行状态 Try ' 启动带控制的上传任务 Await ChunkUploadWithControl(_uploadState, ToolStripProgressBar1, _cts.Token, _pauseEvent) DropLblUid.Text = $"上传成功 ({Now.ToString("hh:mm:ss tt")})" Catch ex As OperationCanceledException DropLblUid.Text = "上传已停止" Catch ex As DropboxException DropLblUid.Text = $"上传出错:{ex.Message}" ' 可选:将_uploadState序列化到本地文件,实现跨会话恢复 Finally ' 重置UI和资源 BackupToolStripMenuItem.Enabled = True DropboxToolStripMenuItem.Enabled = True ToolStripProgressBar1.Visible = False _cts.Dispose() _cts = Nothing ' 删除备份文件 Try File.Delete(newBakFile) Catch ex As IOException MessageBox.Show($"删除备份文件失败:{ex.Message}") End Try End Try End If Catch ex As IOException MessageBox.Show($"操作失败:{ex.Message}") End Try End Sub ' 暂停/恢复按钮事件 Private Sub PauseResumeToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles PauseResumeToolStripMenuItem.Click If _cts Is Nothing OrElse _cts.Token.IsCancellationRequested Then MessageBox.Show("没有正在进行的上传任务!") Return End If If _pauseEvent.IsSet Then ' 暂停上传 _pauseEvent.Reset() PauseResumeToolStripMenuItem.Text = "恢复上传" DropLblUid.Text = "上传已暂停" Else ' 恢复上传 _pauseEvent.Set() PauseResumeToolStripMenuItem.Text = "暂停上传" DropLblUid.Text = "继续上传中..." End If End Sub ' 停止按钮事件 Private Sub StopUploadToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles StopUploadToolStripMenuItem.Click If _cts Is Nothing OrElse _cts.Token.IsCancellationRequested Then MessageBox.Show("没有正在进行的上传任务!") Return End If ' 发送停止指令,并解除暂停阻塞 _cts.Cancel() _pauseEvent.Set() PauseResumeToolStripMenuItem.Text = "暂停上传" DropLblUid.Text = "上传已停止" End Sub End Class
关键注意事项
- 避免
Application.DoEvents():改用Invoke更新UI,防止线程死锁和界面假死。 - 会话有效期:Dropbox的上传会话默认24小时有效,如果暂停超过24小时,需要重新创建会话。
- 跨会话恢复:如果需要关闭程序后恢复上传,可以用Json.NET将
DropboxUploadState序列化到本地文件,下次启动时读取并传入ChunkUploadWithControl。 - 资源清理:确保在任务结束后释放
CancellationTokenSource和文件流资源。
内容的提问来源于stack exchange,提问作者Evry1falls
相关产品推荐
相关产品推荐

