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

如何实现不同BackgroundWorker实例访问同一文件时不锁定源文件

问题核心原因

你遇到的多设备同时拷贝就异常终止的问题,和BackgroundWorker本身无关,是文件流打开参数错误、异常捕获逻辑有遗漏导致的:

  • 你把文件流初始化的代码放在了Try块之外,一旦流打开失败(触发文件占用异常),这部分异常不会被Catch捕获,后台线程会直接抛出未处理异常触发RunWorkerCompleted流程,同时你在RunWorkerCompleted里加了On Error Resume Next,直接吞掉了异常提示,所以看不到任何报错。
  • 源文件打开时不必要地申请了读写权限,且共享模式设置不合理,导致第一个进程打开文件后,其余进程无法再获取到匹配的权限打开文件,直接打开失败。

修正后的代码

Private w101 As String
Private SaveDir As String

Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    Dim parts As String() = w101.Split(New Char() {"\"c})
    Dim filename As String = parts(parts.Count - 1)
    ' 目标路径用Path.Combine拼接,避免斜杠错误
    Dim targetPath As String = IO.Path.Combine(SaveDir, filename)
    Dim lngLen As Long = 0
    Dim lnglenres As Long = 0
    Dim byteBuffer(4096) As Byte
    Dim intBytesRead As Integer

    Try
        ' 源文件只申请读权限,共享模式设置为允许其他进程读写,避免锁死文件
        Using streamRead As New System.IO.FileStream(w101, System.IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.ReadWrite)
            lngLen = streamRead.Length
            ' 处理空文件场景,避免除零错误
            If lngLen = 0 Then
                e.Result = "空文件传输完成"
                Exit Sub
            End If
            lnglenres = CLng(Math.Ceiling(lngLen / 1048576))
            setLabelTxt1("STATUS : (0/" & lnglenres.ToString & " MB) Transferred.", KITTASK_media1progress)

            ' 目标文件流也用Using包裹,异常时自动释放
            Using streamWrite As New System.IO.FileStream(targetPath, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.None)
                While (streamWrite.Length < lngLen)
                    If BackgroundWorker1.CancellationPending Then
                        e.Cancel = True
                        Exit While
                    End If
                    BackgroundWorker1.ReportProgress(CLng(streamRead.Position / lngLen * 100))
                    setLabelTxt1("STATUS : (" & CLng(streamRead.Position / 1048576).ToString & " MB / " & lnglenres.ToString & " MB) Transferred.", KITTASK_media1progress)
                    intBytesRead = streamRead.Read(byteBuffer, 0, 4096)
                    streamWrite.Write(byteBuffer, 0, intBytesRead)
                End While
                streamWrite.Flush()
            End Using
        End Using
    Catch ex As Exception
        ' 这里可以记录异常日志,或者弹窗提示,不会再漏报错
        MessageBox.Show("ERROR: " & ex.Message)
        e.Cancel = True
    End Try
End Sub

Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    On Error Resume Next
    ProgressBar1.Value = e.ProgressPercentage
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    On Error Resume Next
    If e.Cancelled = True Then
        MsgBox("File transfer cancelled by user.")
        ProgressBar1.Value = 0
        KITTASK_media1progress.Text = "STATUS : Ready"
    Else
        MsgBox("1 ok")
        ProgressBar1.Value = 0
        KITTASK_media1progress.Text = "STATUS : Ready"
    End If
End Sub

关键修改说明

  1. 把所有文件流操作放到Try块内部,同时用Using语句包裹流,不管运行是否异常都会自动释放文件句柄,不会残留锁。
  2. 源文件打开权限从ReadWrite改为Read,不需要写权限就不要申请,减少冲突概率。
  3. 源文件共享模式从FileShare.Read改为FileShare.ReadWrite,允许其他进程同时读写该文件,不会被当前进程锁死。
  4. 修复了空文件、文件长度计算错误可能导致的除零、进度计算错误问题。
  5. 用Path.Combine拼接目标路径,避免手动拼接斜杠导致的路径错误。

内容的提问来源于stack exchange,提问作者Walter P Steiner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 04:45:03