' 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 '统计线程
PrivateSub StartCopy_Click()Sub StartCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartCopy.Click '开始拷贝 ' Validate from and to folders IfNot SetRootPath ThenExit Sub IfNot CheckFromPath() ThenExit Sub IfNot CheckToPath() ThenExit Sub ' Create an instance of the copy class that will be assigned to the first thread. DimFileCopyAsNew 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(AddressOfFileCopy.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 AsNew 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
下面是终止两个线程的代码:
PrivateSub StopCopy_Click()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方法,用来响应子线程的回调,刷新主界面
PublicSub CopyThreadMessage()Sub CopyThreadMessage(ByVal ThreadName AsString, ByVal CopiedFiles AsLong, ByVal Message AsString) ' 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 EndIf ' Show current file txtFile.Text ="Copying: "& Message ' Update progressbar If ProgressBar1.Maximum <>0Then ProgressBar1.Value = _totalFiles - (_totalFiles - CopiedFiles) ' Update status (TotalFiles not zero means counting has finished) If _totalFiles <>0Then lblStatus.Text ="Status: Copying. There are "+ _totalFiles.ToString +" files in "+ _totalFolders.ToString +" folders. Files copied so far "& CopiedFiles &"." EndIf ' Save for CountThreadMessage() _copiedFiles = CopiedFiles End Sub PublicSub CountThreadMessage()Sub CountThreadMessage(ByVal ThreadName AsString, ByVal Files AsLong, ByVal TotalFiles AsLong, ByVal Folders AsLong, ByVal Message AsString) ' 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) EndIf End Sub
负责拷贝和统计的类:
Imports System.Threading Imports System.IO PublicClass CopyClassClass 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 PrivateDelegateSub CallClientCopy()Sub CallClientCopy(ByVal ThreadName AsString, ByVal FilesRemaining AsLong, ByVal Message AsString) 'Create a delegate method that will map to the CountThreadMessage method of the client app PrivateDelegateSub CallClientCount()Sub CallClientCount(ByVal ThreadName AsString, ByVal TotalFiles AsLong, ByVal TotalFolders AsLong, ByVal Files AsLong, ByVal Message AsString) 'Create an object for each deletegate Private _callClientCopy As CallClientCopy Private _callClientCount As CallClientCount ' Property variables Private _firstTime AsBoolean Private _fromPath AsString Private _toPath AsString Private _directories AsLong Private _files AsLong Private _copiedFiles AsLong Private _totalFiles AsLong Private _fileName AsString Private _logFile As StreamWriter Private _startDateTime AsDate Private _logFileName AsString ' Constants PrivateConst LOG_FILE AsString="BackupLog.txt" PrivateConst ERR_MSG AsString="Error accessing file: " PublicSub New()SubNew(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 PublicSub CopyFiles()Sub CopyFiles() 'Do the work of the first thread here ' Give this thread a name If Thread.CurrentThread.Name =NothingThen Thread.CurrentThread.Name ="Copy" ' Create a new DirectoryInfo object for from path. DimdirAsNew 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 PublicSub GetCountData()Sub GetCountData() 'Do the work of the second thread here ' Give this thread a name If Thread.CurrentThread.Name =NothingThen Thread.CurrentThread.Name ="Count" ' Create a new DirectoryInfo object for from path. DimdirAsNew 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 PrivateSub ReallyCopyFiles()Sub ReallyCopyFiles(ByVal FSInfo As FileSystemInfo()) ' Check the FSInfo parameter. If FSInfo IsNothingThen ThrowNew ArgumentNullException("FSInfo") EndIf ' Iterate through each item. Dim i As FileSystemInfo ForEach i In FSInfo Try ' Check to see if this is a DirectoryInfo object. IfTypeOf 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. ElseIfTypeOf i Is FileInfo Then 'save the full path and file name _fileName = i.FullName 'Get the copy path name only Dim copypath AsString= ToPath &Mid(_fileName, Len(FromPath) +1, Len(_fileName) -Len(FromPath) -Len(i.Name)) 'Create copy path if it does not exist IfNot Directory.Exists(copypath) Then Directory.CreateDirectory(copypath) EndIf ' Get the to path and filename Dim tofile AsString= ToPath &Mid(_fileName, Len(FromPath) +1) ' Update status info on client Dim fi AsNew FileInfo(_fileName) Dim Message AsString= _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 AsBoolean=True If File.Exists(tofile) Then If File.GetLastWriteTime(_fileName) = File.GetLastWriteTime(tofile) Then OkayToCopy =False EndIf EndIf ' Copy file with overwrite If OkayToCopy Then File.Copy(_fileName, tofile, True) ' Increment copied file count _copiedFiles +=1 EndIf Catch ex As Exception ' Report error but continue processing WriteLog(ERR_MSG & _fileName & vbCrLf & ex.Message.ToString) EndTry Next i End Sub PrivateSub CountFiles()Sub CountFiles(ByVal FSInfo As FileSystemInfo()) Static ShowCount AsLong=0 ' Check the FSInfo parameter. If FSInfo IsNothingThen ThrowNew ArgumentNullException("FSInfo") EndIf ' Iterate through each item. Dim i As FileSystemInfo ForEach i In FSInfo Try ' Check to see if this is a DirectoryInfo object. IfTypeOf 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. ElseIfTypeOf 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 SelectCase ShowCount Case0 ' Display count CallClient(Thread.CurrentThread.Name, _files, _totalFiles, _directories, "") CaseIs>=200 ' Display count CallClient(Thread.CurrentThread.Name, _files, _totalFiles, _directories, "") 'reset so display is every 200 files in folder ShowCount =0 EndSelect 'Increment show count ShowCount +=1 EndIf Catch ex As Exception 'Record error then continue (like a resume next) WriteLog(ERR_MSG & _fileName & vbCrLf & ex.Message.ToString) EndTry Next i End Sub PrivateSub CallClient()Sub CallClient(ByVal ThreadName AsString, ByVal Files AsLong, ByVal TotalFiles AsLong, ByVal Directories AsLong, ByVal Message AsString) SelectCase 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) EndSelect '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 PrivateSub OpenLog()Sub OpenLog() ' Create log file IfNot 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() EndUsing EndIf End Sub PrivateSub WriteLog()Sub WriteLog(ByVal Message AsString) ' 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() EndUsing End Sub PrivateSub CloseLog()Sub CloseLog() If File.Exists(LogFileName) Then _logFile.Close() End Sub PrivateProperty FirstTime()Property FirstTime() AsBoolean Get Return _firstTime EndGet Set(ByVal value AsBoolean) _firstTime = value EndSet End Property PublicProperty FromPath()Property FromPath() AsString Get Return _fromPath EndGet Set(ByVal value AsString) _fromPath = value EndSet End Property PublicProperty ToPath()Property ToPath() AsString Get Return _toPath EndGet Set(ByVal value AsString) _toPath = value EndSet End Property PublicProperty StartDateTime()Property StartDateTime() AsDate Get Return _startDateTime EndGet Set(ByVal value AsDate) _startDateTime = value EndSet End Property PublicReadOnlyProperty LogFileName()Property LogFileName() AsString Get ReturnFormat(StartDateTime, "yyMMdd-hhmmss") &"-"& LOG_FILE EndGet End Property PublicReadOnlyProperty Directories()Property Directories() AsLong Get Return _directories EndGet End Property PublicReadOnlyProperty Files()Property Files() AsLong Get Return _files EndGet End Property PublicReadOnlyProperty TotalFiles()Property TotalFiles() AsLong Get Return _totalFiles EndGet End Property End Class