zoukankan      html  css  js  c++  java
  • 多线程文件备份(VB.NET版)

    简介

    多线程迟早是我们要面对的一个东西,本文向你展示了一个简单的 使用两个线程来拷贝文件的应用程序

    Backup将一个目录中文件拷贝到另一个目录中,它使用了一个线程来显示 正被拷贝的文件名称,另一个线程用来在拷贝的文件的同时统计文件数目和文件夹数目。这就意味着在拷贝可以开始之前不用浪费时间去等待文件数目的统计完成, 我们使用了两个线程同时完成拷贝和统计工作。

    Backup对于大数量文件的拷贝也是快速和有效率的。它很快是因为当目标 文件已经存在并且没有改变过时就不做拷贝工作,因此它对于重复拷贝来说不错,因为它只拷贝新文件或更新过的文件。

    这个程序的另一个特点是当在一个特点文件上发生安全性错误或其 他类型错误(当然不包括硬件错误),它不会停止拷贝工作,它将会记录下错误信息并继续完成工作。过后你可以去查看日志文件,它会告诉你发生了什么错误。大 部分错误都是由于安全配置问题产生的。

    背景知识

    为什么要使用多线程呢?一个原因可能一个窗口在忙碌时,你想能 点击窗口上的一个按钮。另一个原因是多核时代已经来临,硬件和操作系统级别的多任务也存在,线程无可避免,尤其当我们关注性能时。

    好的,你已经决定你想在.Net中使用多线程。你可以使用BackgroundWorker, 不过我假定你应该从System.Threading开始,并直接使用Thread类。个人看来,它更容易使用,并且更具灵活性。

    那么线程到底是什么呢?它就好比于一个源自于你的主程序的另一 个完全分离的程序。一旦线程启动,主程序对线程完全不知道。它们生死自控。要启动一个或两个线程,你可能想知道如何创建线程,如何传递数据,如何从子线程 中回调主应用程序以及主应用程序如何知道是哪个子线程回调了它?下面的代码片段会回答这些问题的。

    最后一点,作者将一个类实例的方法赋予了一个线程,尽管可以将 主程序的方法赋予线程,但作者认为这样做更好。


        
    ' Declare first thread variable. This will be used to copy the files.
        Private CopyThread As Thread '拷贝线程

        
    ' Delclare second thread variable. This will be used to count the folders and files.
    Private CountThread As Thread '统计线程

    统计线程一般在拷贝线程前面完成,除非你拷贝的文件数目很小, 那种情况下一切都发生的很快。

    另一方面,统计线程结束后,总文件数目会被统计出来,从而用来 设置ProgressBar1.Max属性,

    下面是启动拷贝线程和统计线程的代码:

      Private Sub StartCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartCopy.Click
            
    '开始拷贝
            ' Validate from and to folders
            If Not SetRootPath Then Exit Sub
            
    If Not CheckFromPath() Then Exit Sub
            
    If Not CheckToPath() Then Exit Sub

            
    ' Create an instance of the copy class that will be assigned to the first thread.
            Dim FileCopy As New CopyClass(Me)

            
    ' Set required properties
            FileCopy.FromPath = FromPathTextbox.Text
            
    FileCopy.ToPath = ToPathTextbox.Text & _rootDir
            
    FileCopy.StartDateTime = DateTime.Now

            
    'Save log file name
            _logFile = FileCopy.LogFileName

            
    ' Create the thread and assign the class instance and method to execute 
            ' (CopyFiles in this case) when the thread is started.
            CopyThread = New Thread(AddressOf FileCopy.CopyFiles) '拷贝线程

            
    ' Start the first thread to copy the files.
            CopyThread.Name = "Copy"
            CopyThread.IsBackground 
    = True
            CopyThread.Start()

            
    ' Create another instance of the copy class that will be assigned to the second thread.
            Dim FileFolderCount As New CopyClass(Me)

            
    ' Set required properties
            FileFolderCount.FromPath = FromPathTextbox.Text
            FileFolderCount.ToPath 
    = ToPathTextbox.Text

            
    ' Create the thread and assign the class instance and method to execute 
            ' (CopyFiles in this case) when the thread is started.
            CountThread = New Thread(AddressOf FileFolderCount.GetCountData) '计数线程

            
    ' Start the second thread to count folders and files while the copy is running at the same time.
            CountThread.Name = "Count"
            CountThread.IsBackground 
    = True
            CountThread.Start()

            
    ' Reset form controls
            StartCopy.Enabled = False
            Panel1.Enabled 
    = False
            StopCopy.Enabled 
    = True

        
    End Sub

    下面是终止两个线程的代码:

        Private Sub StopCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StopCopy.Click
            
    '终止线程
            If CopyThread.IsAlive Then CopyThread.Abort()
            
    If CountThread.IsAlive Then CountThread.Abort()
        
    End Sub

    主界面的两个delegate方法,用来响应子线程的回调,刷新主界面

        Public Sub CopyThreadMessage(ByVal ThreadName As StringByVal CopiedFiles As LongByVal Message As String)

            
    ' If finished copying
            If Message = "END" Then
                lblStatus.Text 
    = "Status: Copy Finsihed. Copied " + _totalFiles.ToString + " files in " + _totalFolders.ToString + " folders."
                txtFile.Text 
    = "Copy completed successfully."
                ProgressBar1.Value 
    = ProgressBar1.Maximum
                CopyThread.Abort()
                CountThread.Abort()
                
    Exit Sub
            
    End If

            
    ' Show current file
            txtFile.Text = "Copying: " & Message

            
    ' Update progressbar
            If ProgressBar1.Maximum <> 0 Then ProgressBar1.Value = _totalFiles - (_totalFiles - CopiedFiles)

            
    ' Update status (TotalFiles not zero means counting has finished)
            If _totalFiles <> 0 Then
                lblStatus.Text 
    = "Status: Copying. There are " + _totalFiles.ToString + " files in " + _totalFolders.ToString + " folders. Files copied so far " & CopiedFiles & "."
            
    End If

            
    ' Save for CountThreadMessage()
            _copiedFiles = CopiedFiles

        
    End Sub

        
    Public Sub CountThreadMessage(ByVal ThreadName As StringByVal Files As LongByVal TotalFiles As LongByVal Folders As LongByVal Message As String)

            
    ' Display current count
            lblStatus.Text = "Status: Copying and Counting. So far there are " + Files.ToString + " files in " + Folders.ToString + " folders."

            
    ' Save totals when finished counting for CopyThreadMessage()
            If Message = "END" Then
                _totalFiles 
    = TotalFiles
                _totalFolders 
    = Folders
                lblStatus.Text 
    = "Status: Copying. There are " + _totalFiles.ToString + " files in " + _totalFolders.ToString + " folders. Files copied so far " & _copiedFiles & "."
                ProgressBar1.Maximum 
    = _totalFiles
                ProgressBar1.Value 
    = _totalFiles - (_totalFiles - _copiedFiles)
            
    End If

        
    End Sub

    负责拷贝和统计的类:

    Imports System.Threading
    Imports System.IO
    Public Class CopyClass
        
    'This will hold the reference to the client form
        Private _clientApp As Form

        
    'Create a delegate method that will map to the CopyThreadMessage method of the client app
        Private Delegate Sub CallClientCopy(ByVal ThreadName As StringByVal FilesRemaining As LongByVal Message As String)

       
    'Create a delegate method that will map to the CountThreadMessage method of the client app
        Private Delegate Sub CallClientCount(ByVal ThreadName As StringByVal TotalFiles As LongByVal TotalFolders As LongByVal Files As LongByVal Message As String)

        
    'Create an object for each deletegate
        Private _callClientCopy As CallClientCopy
        
    Private _callClientCount As CallClientCount

        
    ' Property variables
        Private _firstTime As Boolean
        
    Private _fromPath As String
        
    Private _toPath As String
        
    Private _directories As Long
        
    Private _files As Long
        
    Private _copiedFiles As Long
        
    Private _totalFiles As Long
        
    Private _fileName As String
        
    Private _logFile As StreamWriter
        
    Private _startDateTime As Date
        
    Private _logFileName As String

        
    ' Constants
        Private Const LOG_FILE As String = "BackupLog.txt"
        
    Private Const ERR_MSG As String = "Error accessing file: "
        
    Public Sub New(ByRef ClientApp As Backup)

            
    ' Save the reference to the client app
            _clientApp = ClientApp

            
    ' Assign delegate objects
            _callClientCopy = AddressOf ClientApp.CopyThreadMessage
            _callClientCount 
    = AddressOf ClientApp.CountThreadMessage

        
    End Sub

        
    Public Sub CopyFiles()
            
    'Do the work of the first thread here

            
    ' Give this thread a name
            If Thread.CurrentThread.Name = Nothing Then Thread.CurrentThread.Name = "Copy"

            
    ' Create a new DirectoryInfo object for from path.
            Dim dir As New DirectoryInfo(FromPath)

            
    ' Call the GetFileSystemInfos method.
            Dim FSinfo As FileSystemInfo() = dir.GetFileSystemInfos

            
    ' Open log file
            OpenLog()

            
    'Copy one file at a time looping until all files are copied
            ReallyCopyFiles(FSinfo)

            WriteLog(
    "Copy completed successfully.")

            
    'Call client one last time to signal end of copy
            CallClient(Thread.CurrentThread.Name, _copiedFiles, _totalFiles, _directories, "END")

        
    End Sub

        
    Public Sub GetCountData()
            
    'Do the work of the second thread here

            
    ' Give this thread a name
            If Thread.CurrentThread.Name = Nothing Then Thread.CurrentThread.Name = "Count"

            
    ' Create a new DirectoryInfo object for from path.
            Dim dir As New DirectoryInfo(FromPath)

            
    ' Call the GetFileSystemInfos method.
            Dim FSinfo As FileSystemInfo() = dir.GetFileSystemInfos

            
    ' Count folder and files
            CountFiles(FSinfo)

            
    ' Save total files count
            _totalFiles = _files

            
    ' Send message to client form
            CallClient(Thread.CurrentThread.Name, _files, _totalFiles, _directories, "END")

        
    End Sub

        
    Private Sub ReallyCopyFiles(ByVal FSInfo As FileSystemInfo())
            
    ' Check the FSInfo parameter.
            If FSInfo Is Nothing Then
                
    Throw New ArgumentNullException("FSInfo")
            
    End If

            
    ' Iterate through each item.
            Dim i As FileSystemInfo
            
    For Each i In FSInfo

                
    Try
                    
    ' Check to see if this is a DirectoryInfo object.
                    If TypeOf i Is DirectoryInfo Then
                        
    ' Cast the object to a DirectoryInfo object.
                        Dim dInfo As DirectoryInfo = CType(i, DirectoryInfo)

                        
    ' Iterate (recurse) through all sub-directories.
                        ReallyCopyFiles(dInfo.GetFileSystemInfos())
                        
    ' Check to see if this is a FileInfo object.
                    ElseIf TypeOf i Is FileInfo Then
                        
    'save the full path and file name
                        _fileName = i.FullName

                        
    'Get the copy path name only
                        Dim copypath As String = ToPath & Mid(_fileName, Len(FromPath) + 1Len(_fileName) - Len(FromPath) - Len(i.Name))

                        
    'Create copy path if it does not exist
                        If Not Directory.Exists(copypath) Then
                            Directory.CreateDirectory(copypath)
                        
    End If

                        
    ' Get the to path and filename
                        Dim tofile As String = ToPath & Mid(_fileName, Len(FromPath) + 1)

                        
    ' Update status info on client
                        Dim fi As New FileInfo(_fileName)
                        
    Dim Message As String = _fileName & " is " & Decimal.Round(CDec(fi.Length / 1048576), 2& "MB in length."
                        CallClient(Thread.CurrentThread.Name, _copiedFiles, _totalFiles, _directories, Message)

                        
    ' if file exists check if file has been updated since last copy
                        Dim OkayToCopy As Boolean = True
                        
    If File.Exists(tofile) Then
                            
    If File.GetLastWriteTime(_fileName) = File.GetLastWriteTime(tofile) Then
                                OkayToCopy 
    = False
                            
    End If
                        
    End If

                        
    ' Copy file with overwrite
                        If OkayToCopy Then File.Copy(_fileName, tofile, True)

                        
    ' Increment copied file count
                        _copiedFiles += 1

                    
    End If
                
    Catch ex As Exception
                    
    ' Report error but continue processing
                    WriteLog(ERR_MSG & _fileName & vbCrLf & ex.Message.ToString)
                
    End Try

            
    Next i

        
    End Sub

        
    Private Sub CountFiles(ByVal FSInfo As FileSystemInfo())
            
    Static ShowCount As Long = 0

            
    ' Check the FSInfo parameter.
            If FSInfo Is Nothing Then
                
    Throw New ArgumentNullException("FSInfo")
            
    End If

            
    ' Iterate through each item.
            Dim i As FileSystemInfo
            
    For Each i In FSInfo

                
    Try
                    
    ' Check to see if this is a DirectoryInfo object.
                    If TypeOf i Is DirectoryInfo Then
                        
    ' Add one to the directory count.
                        _directories += 1

                        
    ' Cast the object to a DirectoryInfo object.
                        Dim dInfo As DirectoryInfo = CType(i, DirectoryInfo)

                        
    ' Iterate (recurse) through all sub-directories.
                        CountFiles(dInfo.GetFileSystemInfos())
                        
    ' Check to see if this is a FileInfo object.
                    ElseIf TypeOf i Is FileInfo Then
                        
    ' Add one to the file count.
                        _files += 1

                        
    'display count for first file in every folder then every 200 - for faster performance
                        Select Case ShowCount
                            
    Case 0
                                
    ' Display count
                                CallClient(Thread.CurrentThread.Name, _files, _totalFiles, _directories, "")
                            
    Case Is >= 200
                                
    ' Display count
                                CallClient(Thread.CurrentThread.Name, _files, _totalFiles, _directories, "")

                                
    'reset so display is every 200 files in folder
                                ShowCount = 0
                        
    End Select

                        
    'Increment show count
                        ShowCount += 1

                    
    End If
                
    Catch ex As Exception
                    
    'Record error then continue (like a resume next)
                    WriteLog(ERR_MSG & _fileName & vbCrLf & ex.Message.ToString)
                
    End Try

            
    Next i

        
    End Sub

        
    Private Sub CallClient(ByVal ThreadName As StringByVal Files As LongByVal TotalFiles As LongByVal Directories As LongByVal Message As String)

            
    Select Case ThreadName
                
    Case "Copy"
                    
    'Call the delegated method
                    _clientApp.Invoke(_callClientCopy, ThreadName, Files, Message)
                
    Case "Count"
                    
    'Call the delegated method
                    _clientApp.Invoke(_callClientCount, ThreadName, Files, TotalFiles, Directories, Message)
            
    End Select

            
    'Let the thread sleep before continuing so the client app will have time to be process (1 millisecond is enough)
            Thread.Sleep(0)
        
    End Sub

        
    Private Sub OpenLog()

            
    ' Create log file
            If Not File.Exists(StartDateTime & "-" & LOG_FILE) Then
                
    Using _logFile As StreamWriter = File.CreateText(LogFileName)
                    _logFile.WriteLine(
    "Logfile name is: " & LogFileName)
                    _logFile.WriteLine(
    "BACKUP LOG FILE STARTED AT: " & StartDateTime.ToString)
                    _logFile.WriteLine(
    "================================================")
                    _logFile.Write(
    "Copying FROM: " & _fromPath)
                    _logFile.WriteLine()
                    _logFile.Write(
    "Copying TO: " & _toPath)
                    _logFile.WriteLine()
                    _logFile.Close()
                
    End Using
            
    End If

        
    End Sub

        
    Private Sub WriteLog(ByVal Message As String)

            
    ' Create an instance of StreamWriter to write text to a file.
            Using _logFile As StreamWriter = File.AppendText(LogFileName)
                
    ' Add some text to the file.
                _logFile.WriteLine()
                _logFile.WriteLine(
    "TIME OF LOG ENTRY: " & DateTime.Now)
                
    ' Arbitrary objects can also be written to the file.
                _logFile.WriteLine(Message)
                _logFile.Flush()
                _logFile.Close()
            
    End Using

        
    End Sub

        
    Private Sub CloseLog()
            
    If File.Exists(LogFileName) Then _logFile.Close()
        
    End Sub

        
    Private Property FirstTime() As Boolean
            
    Get
                
    Return _firstTime
            
    End Get
            
    Set(ByVal value As Boolean)
                _firstTime 
    = value
            
    End Set
        
    End Property

        
    Public Property FromPath() As String
            
    Get
                
    Return _fromPath
            
    End Get
            
    Set(ByVal value As String)
                _fromPath 
    = value
            
    End Set
        
    End Property

        
    Public Property ToPath() As String
            
    Get
                
    Return _toPath
            
    End Get
            
    Set(ByVal value As String)
                _toPath 
    = value
            
    End Set
        
    End Property

        
    Public Property StartDateTime() As Date
            
    Get
                
    Return _startDateTime
            
    End Get
            
    Set(ByVal value As Date)
                _startDateTime 
    = value
            
    End Set
        
    End Property

        
    Public ReadOnly Property LogFileName() As String
            
    Get
                
    Return Format(StartDateTime, "yyMMdd-hhmmss"& "-" & LOG_FILE
            
    End Get
        
    End Property

        
    Public ReadOnly Property Directories() As Long
            
    Get
                
    Return _directories
            
    End Get
        
    End Property

        
    Public ReadOnly Property Files() As Long
            
    Get
                
    Return _files
            
    End Get
        
    End Property

        
    Public ReadOnly Property TotalFiles() As Long
            
    Get
                
    Return _totalFiles
            
    End Get
        
    End Property


    End Class

    简介

    多线程迟早是我们要面对的一个东西,本文向你展示了一个简单的 使用两个线程来拷贝文件的应用程序

    Backup将一个目录中文件拷贝到另一个目录中,它使用了一个线程来显示 正被拷贝的文件名称,另一个线程用来在拷贝的文件的同时统计文件数目和文件夹数目。这就意味着在拷贝可以开始之前不用浪费时间去等待文件数目的统计完成, 我们使用了两个线程同时完成拷贝和统计工作。

    Backup对于大数量文件的拷贝也是快速和有效率的。它很快是因为当目标 文件已经存在并且没有改变过时就不做拷贝工作,因此它对于重复拷贝来说不错,因为它只拷贝新文件或更新过的文件。

    这个程序的另一个特点是当在一个特点文件上发生安全性错误或其 他类型错误(当然不包括硬件错误),它不会停止拷贝工作,它将会记录下错误信息并继续完成工作。过后你可以去查看日志文件,它会告诉你发生了什么错误。大 部分错误都是由于安全配置问题产生的。

    背景知识

    为什么要使用多线程呢?一个原因可能一个窗口在忙碌时,你想能 点击窗口上的一个按钮。另一个原因是多核时代已经来临,硬件和操作系统级别的多任务也存在,线程无可避免,尤其当我们关注性能时。

    好的,你已经决定你想在.Net中使用多线程。你可以使用BackgroundWorker, 不过我假定你应该从System.Threading开始,并直接使用Thread类。个人看来,它更容易使用,并且更具灵活性。

    那么线程到底是什么呢?它就好比于一个源自于你的主程序的另一 个完全分离的程序。一旦线程启动,主程序对线程完全不知道。它们生死自控。要启动一个或两个线程,你可能想知道如何创建线程,如何传递数据,如何从子线程 中回调主应用程序以及主应用程序如何知道是哪个子线程回调了它?下面的代码片段会回答这些问题的。

    最后一点,作者将一个类实例的方法赋予了一个线程,尽管可以将 主程序的方法赋予线程,但作者认为这样做更好。


        
    ' Declare first thread variable. This will be used to copy the files.
        Private CopyThread As Thread '拷贝线程

        
    ' Delclare second thread variable. This will be used to count the folders and files.
    Private CountThread As Thread '统计线程

    统计线程一般在拷贝线程前面完成,除非你拷贝的文件数目很小, 那种情况下一切都发生的很快。

    另一方面,统计线程结束后,总文件数目会被统计出来,从而用来 设置ProgressBar1.Max属性,

    下面是启动拷贝线程和统计线程的代码:

      Private Sub StartCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartCopy.Click
            
    '开始拷贝
            ' Validate from and to folders
            If Not SetRootPath Then Exit Sub
            
    If Not CheckFromPath() Then Exit Sub
            
    If Not CheckToPath() Then Exit Sub

            
    ' Create an instance of the copy class that will be assigned to the first thread.
            Dim FileCopy As New CopyClass(Me)

            
    ' Set required properties
            FileCopy.FromPath = FromPathTextbox.Text
            
    FileCopy.ToPath = ToPathTextbox.Text & _rootDir
            
    FileCopy.StartDateTime = DateTime.Now

            
    'Save log file name
            _logFile = FileCopy.LogFileName

            
    ' Create the thread and assign the class instance and method to execute 
            ' (CopyFiles in this case) when the thread is started.
            CopyThread = New Thread(AddressOf FileCopy.CopyFiles) '拷贝线程

            
    ' Start the first thread to copy the files.
            CopyThread.Name = "Copy"
            CopyThread.IsBackground 
    = True
            CopyThread.Start()

            
    ' Create another instance of the copy class that will be assigned to the second thread.
            Dim FileFolderCount As New CopyClass(Me)

            
    ' Set required properties
            FileFolderCount.FromPath = FromPathTextbox.Text
            FileFolderCount.ToPath 
    = ToPathTextbox.Text

            
    ' Create the thread and assign the class instance and method to execute 
            ' (CopyFiles in this case) when the thread is started.
            CountThread = New Thread(AddressOf FileFolderCount.GetCountData) '计数线程

            
    ' Start the second thread to count folders and files while the copy is running at the same time.
            CountThread.Name = "Count"
            CountThread.IsBackground 
    = True
            CountThread.Start()

            
    ' Reset form controls
            StartCopy.Enabled = False
            Panel1.Enabled 
    = False
            StopCopy.Enabled 
    = True

        
    End Sub

    下面是终止两个线程的代码:

        Private Sub StopCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StopCopy.Click
            
    '终止线程
            If CopyThread.IsAlive Then CopyThread.Abort()
            
    If CountThread.IsAlive Then CountThread.Abort()
        
    End Sub

    主界面的两个delegate方法,用来响应子线程的回调,刷新主界面

        Public Sub CopyThreadMessage(ByVal ThreadName As StringByVal CopiedFiles As LongByVal Message As String)

            
    ' If finished copying
            If Message = "END" Then
                lblStatus.Text 
    = "Status: Copy Finsihed. Copied " + _totalFiles.ToString + " files in " + _totalFolders.ToString + " folders."
                txtFile.Text 
    = "Copy completed successfully."
                ProgressBar1.Value 
    = ProgressBar1.Maximum
                CopyThread.Abort()
                CountThread.Abort()
                
    Exit Sub
            
    End If

            
    ' Show current file
            txtFile.Text = "Copying: " & Message

            
    ' Update progressbar
            If ProgressBar1.Maximum <> 0 Then ProgressBar1.Value = _totalFiles - (_totalFiles - CopiedFiles)

            
    ' Update status (TotalFiles not zero means counting has finished)
            If _totalFiles <> 0 Then
                lblStatus.Text 
    = "Status: Copying. There are " + _totalFiles.ToString + " files in " + _totalFolders.ToString + " folders. Files copied so far " & CopiedFiles & "."
            
    End If

            
    ' Save for CountThreadMessage()
            _copiedFiles = CopiedFiles

        
    End Sub

        
    Public Sub CountThreadMessage(ByVal ThreadName As StringByVal Files As LongByVal TotalFiles As LongByVal Folders As LongByVal Message As String)

            
    ' Display current count
            lblStatus.Text = "Status: Copying and Counting. So far there are " + Files.ToString + " files in " + Folders.ToString + " folders."

            
    ' Save totals when finished counting for CopyThreadMessage()
            If Message = "END" Then
                _totalFiles 
    = TotalFiles
                _totalFolders 
    = Folders
                lblStatus.Text 
    = "Status: Copying. There are " + _totalFiles.ToString + " files in " + _totalFolders.ToString + " folders. Files copied so far " & _copiedFiles & "."
                ProgressBar1.Maximum 
    = _totalFiles
                ProgressBar1.Value 
    = _totalFiles - (_totalFiles - _copiedFiles)
            
    End If

        
    End Sub

    负责拷贝和统计的类:

    Imports System.Threading
    Imports System.IO
    Public Class CopyClass
        
    'This will hold the reference to the client form
        Private _clientApp As Form

        
    'Create a delegate method that will map to the CopyThreadMessage method of the client app
        Private Delegate Sub CallClientCopy(ByVal ThreadName As StringByVal FilesRemaining As LongByVal Message As String)

       
    'Create a delegate method that will map to the CountThreadMessage method of the client app
        Private Delegate Sub CallClientCount(ByVal ThreadName As StringByVal TotalFiles As LongByVal TotalFolders As LongByVal Files As LongByVal Message As String)

        
    'Create an object for each deletegate
        Private _callClientCopy As CallClientCopy
        
    Private _callClientCount As CallClientCount

        
    ' Property variables
        Private _firstTime As Boolean
        
    Private _fromPath As String
        
    Private _toPath As String
        
    Private _directories As Long
        
    Private _files As Long
        
    Private _copiedFiles As Long
        
    Private _totalFiles As Long
        
    Private _fileName As String
        
    Private _logFile As StreamWriter
        
    Private _startDateTime As Date
        
    Private _logFileName As String

        
    ' Constants
        Private Const LOG_FILE As String = "BackupLog.txt"
        
    Private Const ERR_MSG As String = "Error accessing file: "
        
    Public Sub New(ByRef ClientApp As Backup)

            
    ' Save the reference to the client app
            _clientApp = ClientApp

            
    ' Assign delegate objects
            _callClientCopy = AddressOf ClientApp.CopyThreadMessage
            _callClientCount 
    = AddressOf ClientApp.CountThreadMessage

        
    End Sub

        
    Public Sub CopyFiles()
            
    'Do the work of the first thread here

            
    ' Give this thread a name
            If Thread.CurrentThread.Name = Nothing Then Thread.CurrentThread.Name = "Copy"

            
    ' Create a new DirectoryInfo object for from path.
            Dim dir As New DirectoryInfo(FromPath)

            
    ' Call the GetFileSystemInfos method.
            Dim FSinfo As FileSystemInfo() = dir.GetFileSystemInfos

            
    ' Open log file
            OpenLog()

            
    'Copy one file at a time looping until all files are copied
            ReallyCopyFiles(FSinfo)

            WriteLog(
    "Copy completed successfully.")

            
    'Call client one last time to signal end of copy
            CallClient(Thread.CurrentThread.Name, _copiedFiles, _totalFiles, _directories, "END")

        
    End Sub

        
    Public Sub GetCountData()
            
    'Do the work of the second thread here

            
    ' Give this thread a name
            If Thread.CurrentThread.Name = Nothing Then Thread.CurrentThread.Name = "Count"

            
    ' Create a new DirectoryInfo object for from path.
            Dim dir As New DirectoryInfo(FromPath)

            
    ' Call the GetFileSystemInfos method.
            Dim FSinfo As FileSystemInfo() = dir.GetFileSystemInfos

            
    ' Count folder and files
            CountFiles(FSinfo)

            
    ' Save total files count
            _totalFiles = _files

            
    ' Send message to client form
            CallClient(Thread.CurrentThread.Name, _files, _totalFiles, _directories, "END")

        
    End Sub

        
    Private Sub ReallyCopyFiles(ByVal FSInfo As FileSystemInfo())
            
    ' Check the FSInfo parameter.
            If FSInfo Is Nothing Then
                
    Throw New ArgumentNullException("FSInfo")
            
    End If

            
    ' Iterate through each item.
            Dim i As FileSystemInfo
            
    For Each i In FSInfo

                
    Try
                    
    ' Check to see if this is a DirectoryInfo object.
                    If TypeOf i Is DirectoryInfo Then
                        
    ' Cast the object to a DirectoryInfo object.
                        Dim dInfo As DirectoryInfo = CType(i, DirectoryInfo)

                        
    ' Iterate (recurse) through all sub-directories.
                        ReallyCopyFiles(dInfo.GetFileSystemInfos())
                        
    ' Check to see if this is a FileInfo object.
                    ElseIf TypeOf i Is FileInfo Then
                        
    'save the full path and file name
                        _fileName = i.FullName

                        
    'Get the copy path name only
                        Dim copypath As String = ToPath & Mid(_fileName, Len(FromPath) + 1Len(_fileName) - Len(FromPath) - Len(i.Name))

                        
    'Create copy path if it does not exist
                        If Not Directory.Exists(copypath) Then
                            Directory.CreateDirectory(copypath)
                        
    End If

                        
    ' Get the to path and filename
                        Dim tofile As String = ToPath & Mid(_fileName, Len(FromPath) + 1)

                        
    ' Update status info on client
                        Dim fi As New FileInfo(_fileName)
                        
    Dim Message As String = _fileName & " is " & Decimal.Round(CDec(fi.Length / 1048576), 2& "MB in length."
                        CallClient(Thread.CurrentThread.Name, _copiedFiles, _totalFiles, _directories, Message)

                        
    ' if file exists check if file has been updated since last copy
                        Dim OkayToCopy As Boolean = True
                        
    If File.Exists(tofile) Then
                            
    If File.GetLastWriteTime(_fileName) = File.GetLastWriteTime(tofile) Then
                                OkayToCopy 
    = False
                            
    End If
                        
    End If

                        
    ' Copy file with overwrite
                        If OkayToCopy Then File.Copy(_fileName, tofile, True)

                        
    ' Increment copied file count
                        _copiedFiles += 1

                    
    End If
                
    Catch ex As Exception
                    
    ' Report error but continue processing
                    WriteLog(ERR_MSG & _fileName & vbCrLf & ex.Message.ToString)
                
    End Try

            
    Next i

        
    End Sub

        
    Private Sub CountFiles(ByVal FSInfo As FileSystemInfo())
            
    Static ShowCount As Long = 0

            
    ' Check the FSInfo parameter.
            If FSInfo Is Nothing Then
                
    Throw New ArgumentNullException("FSInfo")
            
    End If

            
    ' Iterate through each item.
            Dim i As FileSystemInfo
            
    For Each i In FSInfo

                
    Try
                    
    ' Check to see if this is a DirectoryInfo object.
                    If TypeOf i Is DirectoryInfo Then
                        
    ' Add one to the directory count.
                        _directories += 1

                        
    ' Cast the object to a DirectoryInfo object.
                        Dim dInfo As DirectoryInfo = CType(i, DirectoryInfo)

                        
    ' Iterate (recurse) through all sub-directories.
                        CountFiles(dInfo.GetFileSystemInfos())
                        
    ' Check to see if this is a FileInfo object.
                    ElseIf TypeOf i Is FileInfo Then
                        
    ' Add one to the file count.
                        _files += 1

                        
    'display count for first file in every folder then every 200 - for faster performance
                        Select Case ShowCount
                            
    Case 0
                                
    ' Display count
                                CallClient(Thread.CurrentThread.Name, _files, _totalFiles, _directories, "")
                            
    Case Is >= 200
                                
    ' Display count
                                CallClient(Thread.CurrentThread.Name, _files, _totalFiles, _directories, "")

                                
    'reset so display is every 200 files in folder
                                ShowCount = 0
                        
    End Select

                        
    'Increment show count
                        ShowCount += 1

                    
    End If
                
    Catch ex As Exception
                    
    'Record error then continue (like a resume next)
                    WriteLog(ERR_MSG & _fileName & vbCrLf & ex.Message.ToString)
                
    End Try

            
    Next i

        
    End Sub

        
    Private Sub CallClient(ByVal ThreadName As StringByVal Files As LongByVal TotalFiles As LongByVal Directories As LongByVal Message As String)

            
    Select Case ThreadName
                
    Case "Copy"
                    
    'Call the delegated method
                    _clientApp.Invoke(_callClientCopy, ThreadName, Files, Message)
                
    Case "Count"
                    
    'Call the delegated method
                    _clientApp.Invoke(_callClientCount, ThreadName, Files, TotalFiles, Directories, Message)
            
    End Select

            
    'Let the thread sleep before continuing so the client app will have time to be process (1 millisecond is enough)
            Thread.Sleep(0)
        
    End Sub

        
    Private Sub OpenLog()

            
    ' Create log file
            If Not File.Exists(StartDateTime & "-" & LOG_FILE) Then
                
    Using _logFile As StreamWriter = File.CreateText(LogFileName)
                    _logFile.WriteLine(
    "Logfile name is: " & LogFileName)
                    _logFile.WriteLine(
    "BACKUP LOG FILE STARTED AT: " & StartDateTime.ToString)
                    _logFile.WriteLine(
    "================================================")
                    _logFile.Write(
    "Copying FROM: " & _fromPath)
                    _logFile.WriteLine()
                    _logFile.Write(
    "Copying TO: " & _toPath)
                    _logFile.WriteLine()
                    _logFile.Close()
                
    End Using
            
    End If

        
    End Sub

        
    Private Sub WriteLog(ByVal Message As String)

            
    ' Create an instance of StreamWriter to write text to a file.
            Using _logFile As StreamWriter = File.AppendText(LogFileName)
                
    ' Add some text to the file.
                _logFile.WriteLine()
                _logFile.WriteLine(
    "TIME OF LOG ENTRY: " & DateTime.Now)
                
    ' Arbitrary objects can also be written to the file.
                _logFile.WriteLine(Message)
                _logFile.Flush()
                _logFile.Close()
            
    End Using

        
    End Sub

        
    Private Sub CloseLog()
            
    If File.Exists(LogFileName) Then _logFile.Close()
        
    End Sub

        
    Private Property FirstTime() As Boolean
            
    Get
                
    Return _firstTime
            
    End Get
            
    Set(ByVal value As Boolean)
                _firstTime 
    = value
            
    End Set
        
    End Property

        
    Public Property FromPath() As String
            
    Get
                
    Return _fromPath
            
    End Get
            
    Set(ByVal value As String)
                _fromPath 
    = value
            
    End Set
        
    End Property

        
    Public Property ToPath() As String
            
    Get
                
    Return _toPath
            
    End Get
            
    Set(ByVal value As String)
                _toPath 
    = value
            
    End Set
        
    End Property

        
    Public Property StartDateTime() As Date
            
    Get
                
    Return _startDateTime
            
    End Get
            
    Set(ByVal value As Date)
                _startDateTime 
    = value
            
    End Set
        
    End Property

        
    Public ReadOnly Property LogFileName() As String
            
    Get
                
    Return Format(StartDateTime, "yyMMdd-hhmmss"& "-" & LOG_FILE
            
    End Get
        
    End Property

        
    Public ReadOnly Property Directories() As Long
            
    Get
                
    Return _directories
            
    End Get
        
    End Property

        
    Public ReadOnly Property Files() As Long
            
    Get
                
    Return _files
            
    End Get
        
    End Property

        
    Public ReadOnly Property TotalFiles() As Long
            
    Get
                
    Return _totalFiles
            
    End Get
        
    End Property


    End Class

  • 相关阅读:
    Java 8 Stream流编程学习
    AMD R5 2400G插帧教程
    GCC编译Win图形程序不显示控制台方法
    Linux程序守护脚本
    远程桌面软件RDCMan汉化版
    Java基础知识点
    Java的String类常用方法
    Apache Commons 相关工具类使用
    基于OpenCV的双目视觉匹配测距系统
    异想家Ubuntu安装的软件
  • 原文地址:https://www.cnblogs.com/callbin/p/1675973.html
Copyright © 2011-2022 走看看