【问题标题】:Why copying large files using system.io File.Copy becomes unresponsive/not responding in windows forms.为什么使用 system.io File.Copy 复制大文件在 Windows 窗体中变得无响应/无响应。
【发布时间】:2016-03-27 09:08:53
【问题描述】:

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

我正在使用 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 语言的新手。

任何帮助都会很棒。

【问题讨论】:

    标签: .net vb.net


    【解决方案1】:

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

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

    BackgroundWorderdocumentation and example 可以。在示例中,通过让后台线程休眠片刻来模拟长时间运行的进程。如果这发生在 UI 线程上,那么应用程序将冻结,但应用程序不会冻结,因为它是处于睡眠状态的 BackgroundWorker 线程。步骤是

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

    【讨论】:

    • 感谢您的帮助。这对我了解后台工作人员有很大帮助。
    【解决方案2】:

    其实问题不大。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-04
      • 1970-01-01
      • 2012-12-06
      • 1970-01-01
      • 2016-09-21
      • 2021-07-28
      • 1970-01-01
      相关资源
      最近更新 更多