为什么使用system.io File.Copy复制大文件会在Windows窗体中无响应/无响应。

时间:2016-03-27 09:08:53

标签: .net vb.net

我正在创建一个具有自动备份功能的程序,当我尝试在单个文件夹中复制大量或多个文件时,我的应用程序变得无响应/无响应。

我正在使用 System.IO.File.Copy (来源,目的地)来复制文件。

以下是我复制文件的代码。我还使用进度条指示文件复制过程。

Imports System.IO
Public class Form1
    Private Sub btnDestPath_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBrowseDestPath.Click
        'get destination path from FolderBrowserDialog
        Dim destination As String

        If (FolderBrowserDialog1.ShowDialog() = Windows.Forms.DialogResult.OK) Then
            destination = FolderBrowserDialog1.SelectedPath
            txtDestination.Text = destination
        End If
    End Sub

     Private Sub btnCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCopy.Click
        'set folder to copy files
        Dim sourceFilePath As String = "C:\copyfiles\" 

        'get destinationpath from txtDestination.Text label
        Dim destinationPath As String = txtDestination.Text.Replace(vbCrLf, "")

        'add back slash(\) to destinationPath
        Dim filepath As String = destinationPath & "\"

        'count number of files to copy 
        Dim filecount As String
        filecount = Directory.GetFiles(sourceFilePath).Count

        ProgressBar1.Maximum = 1
        ProgressBar1.Maximum = filecount 'represent the # of files
        ProgressBar1.Step = 1 'step property value of 1 to represent each file being copied

        For Each filename As String In Directory.GetFiles(sourceFilePath)
            'check if files exist or not
            If File.Exists(filename) Then
                Dim dFile As String = String.Empty
                Dim dFilePath As String = String.Empty

                dFile = Path.GetFileName(filename)  'source file filenames
                dFilePath = filepath & dFile  'concatenate filepath and filenames

                File.Copy(filename, dFilePath, True) 'copy files from "c:\copyfiles" folder to destinationPath
                ProgressBar1.PerformStep()
            End If

        Next
        MsgBox("Copy Successful", vbOKOnly, "Message")
    End Sub
End Class

我能做些什么来改进代码。我听说使用BackgroundWorker可以解决问题,但我不知道从哪里开始。我只是.NET语言的新手。

任何帮助都会很棒。

2 个答案:

答案 0 :(得分:4)

您与BackgroundWorker走在正确的轨道上。您当前正在使用用于响应UI的相同线程执行您的工作。这意味着在文件复制完成之前,应用程序“太忙”,无法关注用户点击按钮或执行任何其他操作。

BackgroundWorker在不同的线程上执行该方法,这意味着您的UI线程仍可用于响应用户。您可以让他们执行其他操作,或者您可能只有一个“取消”按钮,允许他们停止操作。

BackgroundWorder的{​​{3}}没问题。在该示例中,通过让后台线程暂时休眠来模拟长时间运行的进程。如果这发生在UI线程上,那么应用程序将冻结,但应用程序不会冻结,因为它是正在休眠的BackgroundWorker线程。步骤是

  • 在表单中添加一个(从工具箱中拖动)
  • BackgroundWorker的{​​{1}}事件执行您的文件复制方法。可以认为这与将代码放入按钮的DoWork事件中相同。
  • 当用户想要开始复制文件时,请致电Click。这开始了后台线程上发生的工作。
  • myFileCopyBackgroundWorkder.RunWorkerAsync();有进度报告来电BackgroundWorker时。然后,表单中的事件处理程序可以向用户显示进度 这很重要,因为您不希望在尝试更新UI的其他线程上运行某些内容。您希望它引发UI线程侦听的事件,并且UI线程更新UI。
  • 如果用户想要取消,请致电ReportProgress()。当您循环浏览文件时,请检查CancelAsync以查看用户是否已从主线程请求取消。如果他们有,你就可以停下来。
  • 当后台进程完成(完成,取消,失败)时,它会引发myFileCopyBackgroundWorkder.CancellationPending事件,以便您可以向用户指示。或者您可能在进程运行时禁用了某些控件(例如禁用“开始”按钮。)当该过程完成后,您可以重新启用它。

答案 1 :(得分:1)

实际上这不是问题。

您已经知道每个进程都有一个工作者(主线程)负责用户界面和用户与程序的交互。当您使用File.Copy()等同步操作开始复制大文件时,此工作程序(主线程)正在忙于复制文件,无法处理UI中的事件或执行任何其他操作,除非同步操作复制文件结束,因此应用程序UI变得无响应。如果等待复制过程结束(即同步操作结束),UI将返回响应状态。

如果你想解决这个问题,你必须使用异步操作(不会因为同步操作读取更多here而阻塞),或者你必须在新的单个线程或{{3}上运行同步操作建议Task。我建议使用异步操作。