You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

关键注意事项

  1. 避免Application.DoEvents():改用Invoke更新UI,防止线程死锁和界面假死。
  2. 会话有效期:Dropbox的上传会话默认24小时有效,如果暂停超过24小时,需要重新创建会话。
  3. 跨会话恢复:如果需要关闭程序后恢复上传,可以用Json.NET将DropboxUploadState序列化到本地文件,下次启动时读取并传入ChunkUploadWithControl。
  4. 资源清理:确保在任务结束后释放CancellationTokenSource和文件流资源。

内容的提问来源于stack exchange,提问作者Evry1falls

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 22:02:30