多线程文件备份(VB.NET版)

原文链接:Multithreading Backup Utility

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

Backup.gif


简介

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

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

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

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

背景知识

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

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

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

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

None.gif
None.gif
'Declarefirstthreadvariable.Thiswillbeusedtocopythefiles.
None.gif
PrivateCopyThreadAsThread'拷贝线程
None.gif

None.gif
'Delclaresecondthreadvariable.Thiswillbeusedtocountthefoldersandfiles.
None.gif
PrivateCountThreadAsThread'统计线程
None.gif

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

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

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

ExpandedBlockStart.gifContractedBlock.gifPrivateSubStartCopy_Click()SubStartCopy_Click(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesStartCopy.Click
InBlock.gif
'开始拷贝
InBlock.gif
'Validatefromandtofolders
InBlock.gif
IfNotSetRootPathThenExitSub
InBlock.gif
IfNotCheckFromPath()ThenExitSub
InBlock.gif
IfNotCheckToPath()ThenExitSub
InBlock.gif
InBlock.gif
'Createaninstanceofthecopyclassthatwillbeassignedtothefirstthread.
InBlock.gif
DimFileCopyAsNewCopyClass(Me)
InBlock.gif
InBlock.gif
'Setrequiredproperties
InBlock.gif
FileCopy.FromPath=FromPathTextbox.Text
InBlock.gif
FileCopy.ToPath=ToPathTextbox.Text&_rootDir
InBlock.gif
FileCopy.StartDateTime=DateTime.Now
InBlock.gif
InBlock.gif
'Savelogfilename
InBlock.gif
_logFile=FileCopy.LogFileName
InBlock.gif
InBlock.gif
'Createthethreadandassigntheclassinstanceandmethodtoexecute
InBlock.gif
'(CopyFilesinthiscase)whenthethreadisstarted.
InBlock.gif
CopyThread=NewThread(AddressOfFileCopy.CopyFiles)'拷贝线程
InBlock.gif

InBlock.gif
'Startthefirstthreadtocopythefiles.
InBlock.gif
CopyThread.Name="Copy"
InBlock.gifCopyThread.IsBackground
=True
InBlock.gifCopyThread.Start()
InBlock.gif
InBlock.gif
'Createanotherinstanceofthecopyclassthatwillbeassignedtothesecondthread.
InBlock.gif
DimFileFolderCountAsNewCopyClass(Me)
InBlock.gif
InBlock.gif
'Setrequiredproperties
InBlock.gif
FileFolderCount.FromPath=FromPathTextbox.Text
InBlock.gifFileFolderCount.ToPath
=ToPathTextbox.Text
InBlock.gif
InBlock.gif
'Createthethreadandassigntheclassinstanceandmethodtoexecute
InBlock.gif
'(CopyFilesinthiscase)whenthethreadisstarted.
InBlock.gif
CountThread=NewThread(AddressOfFileFolderCount.GetCountData)'计数线程
InBlock.gif

InBlock.gif
'Startthesecondthreadtocountfoldersandfileswhilethecopyisrunningatthesametime.
InBlock.gif
CountThread.Name="Count"
InBlock.gifCountThread.IsBackground
=True
InBlock.gifCountThread.Start()
InBlock.gif
InBlock.gif
'Resetformcontrols
InBlock.gif
StartCopy.Enabled=False
InBlock.gifPanel1.Enabled
=False
InBlock.gifStopCopy.Enabled
=True
InBlock.gif
ExpandedBlockEnd.gif
EndSub

None.gif

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

ExpandedBlockStart.gifContractedBlock.gifPrivateSubStopCopy_Click()SubStopCopy_Click(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesStopCopy.Click
InBlock.gif
'终止线程
InBlock.gif
IfCopyThread.IsAliveThenCopyThread.Abort()
InBlock.gif
IfCountThread.IsAliveThenCountThread.Abort()
ExpandedBlockEnd.gif
EndSub

None.gif

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

ExpandedBlockStart.gifContractedBlock.gifPublicSubCopyThreadMessage()SubCopyThreadMessage(ByValThreadNameAsString,ByValCopiedFilesAsLong,ByValMessageAsString)
InBlock.gif
InBlock.gif
'Iffinishedcopying
InBlock.gif
IfMessage="END"Then
InBlock.giflblStatus.Text
="Status:CopyFinsihed.Copied"+_totalFiles.ToString+"filesin"+_totalFolders.ToString+"folders."
InBlock.giftxtFile.Text
="Copycompletedsuccessfully."
InBlock.gifProgressBar1.Value
=ProgressBar1.Maximum
InBlock.gifCopyThread.Abort()
InBlock.gifCountThread.Abort()
InBlock.gif
ExitSub
InBlock.gif
EndIf
InBlock.gif
InBlock.gif
'Showcurrentfile
InBlock.gif
txtFile.Text="Copying:"&Message
InBlock.gif
InBlock.gif
'Updateprogressbar
InBlock.gif
IfProgressBar1.Maximum<>0ThenProgressBar1.Value=_totalFiles-(_totalFiles-CopiedFiles)
InBlock.gif
InBlock.gif
'Updatestatus(TotalFilesnotzeromeanscountinghasfinished)
InBlock.gif
If_totalFiles<>0Then
InBlock.giflblStatus.Text
="Status:Copying.Thereare"+_totalFiles.ToString+"filesin"+_totalFolders.ToString+"folders.Filescopiedsofar"&CopiedFiles&"."
InBlock.gif
EndIf
InBlock.gif
InBlock.gif
'SaveforCountThreadMessage()
InBlock.gif
_copiedFiles=CopiedFiles
InBlock.gif
ExpandedBlockEnd.gif
EndSub

ExpandedBlockStart.gifContractedBlock.gif
PublicSubCountThreadMessage()SubCountThreadMessage(ByValThreadNameAsString,ByValFilesAsLong,ByValTotalFilesAsLong,ByValFoldersAsLong,ByValMessageAsString)
InBlock.gif
InBlock.gif
'Displaycurrentcount
InBlock.gif
lblStatus.Text="Status:CopyingandCounting.Sofarthereare"+Files.ToString+"filesin"+Folders.ToString+"folders."
InBlock.gif
InBlock.gif
'SavetotalswhenfinishedcountingforCopyThreadMessage()
InBlock.gif
IfMessage="END"Then
InBlock.gif_totalFiles
=TotalFiles
InBlock.gif_totalFolders
=Folders
InBlock.giflblStatus.Text
="Status:Copying.Thereare"+_totalFiles.ToString+"filesin"+_totalFolders.ToString+"folders.Filescopiedsofar"&_copiedFiles&"."
InBlock.gifProgressBar1.Maximum
=_totalFiles
InBlock.gifProgressBar1.Value
=_totalFiles-(_totalFiles-_copiedFiles)
InBlock.gif
EndIf
InBlock.gif
ExpandedBlockEnd.gif
EndSub

None.gif

负责拷贝和统计的类:

None.gifImportsSystem.Threading
None.gif
ImportsSystem.IO
ExpandedBlockStart.gifContractedBlock.gif
PublicClassCopyClassClassCopyClass
InBlock.gif
'Thiswillholdthereferencetotheclientform
InBlock.gif
Private_clientAppAsForm
InBlock.gif
InBlock.gif
'CreateadelegatemethodthatwillmaptotheCopyThreadMessagemethodoftheclientapp
ExpandedSubBlockStart.gifContractedSubBlock.gif
PrivateDelegateSubCallClientCopy()SubCallClientCopy(ByValThreadNameAsString,ByValFilesRemainingAsLong,ByValMessageAsString)
InBlock.gif
InBlock.gif
'CreateadelegatemethodthatwillmaptotheCountThreadMessagemethodoftheclientapp
ExpandedSubBlockStart.gifContractedSubBlock.gif
PrivateDelegateSubCallClientCount()SubCallClientCount(ByValThreadNameAsString,ByValTotalFilesAsLong,ByValTotalFoldersAsLong,ByValFilesAsLong,ByValMessageAsString)
InBlock.gif
InBlock.gif
'Createanobjectforeachdeletegate
InBlock.gif
Private_callClientCopyAsCallClientCopy
InBlock.gif
Private_callClientCountAsCallClientCount
InBlock.gif
InBlock.gif
'Propertyvariables
InBlock.gif
Private_firstTimeAsBoolean
InBlock.gif
Private_fromPathAsString
InBlock.gif
Private_toPathAsString
InBlock.gif
Private_directoriesAsLong
InBlock.gif
Private_filesAsLong
InBlock.gif
Private_copiedFilesAsLong
InBlock.gif
Private_totalFilesAsLong
InBlock.gif
Private_fileNameAsString
InBlock.gif
Private_logFileAsStreamWriter
InBlock.gif
Private_startDateTimeAsDate
InBlock.gif
Private_logFileNameAsString
InBlock.gif
InBlock.gif
'Constants
InBlock.gif
PrivateConstLOG_FILEAsString="BackupLog.txt"
InBlock.gif
PrivateConstERR_MSGAsString="Erroraccessingfile:"
ExpandedSubBlockStart.gifContractedSubBlock.gif
PublicSubNew()SubNew(ByRefClientAppAsBackup)
InBlock.gif
InBlock.gif
'Savethereferencetotheclientapp
InBlock.gif
_clientApp=ClientApp
InBlock.gif
InBlock.gif
'Assigndelegateobjects
InBlock.gif
_callClientCopy=AddressOfClientApp.CopyThreadMessage
InBlock.gif_callClientCount
=AddressOfClientApp.CountThreadMessage
InBlock.gif
ExpandedSubBlockEnd.gif
EndSub

ExpandedSubBlockStart.gifContractedSubBlock.gif
PublicSubCopyFiles()SubCopyFiles()
InBlock.gif
'Dotheworkofthefirstthreadhere
InBlock.gif

InBlock.gif
'Givethisthreadaname
InBlock.gif
IfThread.CurrentThread.Name=NothingThenThread.CurrentThread.Name="Copy"
InBlock.gif
InBlock.gif
'CreateanewDirectoryInfoobjectforfrompath.
InBlock.gif
DimdirAsNewDirectoryInfo(FromPath)
InBlock.gif
InBlock.gif
'CalltheGetFileSystemInfosmethod.
InBlock.gif
DimFSinfoAsFileSystemInfo()=dir.GetFileSystemInfos
InBlock.gif
InBlock.gif
'Openlogfile
InBlock.gif
OpenLog()
InBlock.gif
InBlock.gif
'Copyonefileatatimeloopinguntilallfilesarecopied
InBlock.gif
ReallyCopyFiles(FSinfo)
InBlock.gif
InBlock.gifWriteLog(
"Copycompletedsuccessfully.")
InBlock.gif
InBlock.gif
'Callclientonelasttimetosignalendofcopy
InBlock.gif
CallClient(Thread.CurrentThread.Name,_copiedFiles,_totalFiles,_directories,"END")
InBlock.gif
ExpandedSubBlockEnd.gif
EndSub

ExpandedSubBlockStart.gifContractedSubBlock.gif
PublicSubGetCountData()SubGetCountData()
InBlock.gif
'Dotheworkofthesecondthreadhere
InBlock.gif

InBlock.gif
'Givethisthreadaname
InBlock.gif
IfThread.CurrentThread.Name=NothingThenThread.CurrentThread.Name="Count"
InBlock.gif
InBlock.gif
'CreateanewDirectoryInfoobjectforfrompath.
InBlock.gif
DimdirAsNewDirectoryInfo(FromPath)
InBlock.gif
InBlock.gif
'CalltheGetFileSystemInfosmethod.
InBlock.gif
DimFSinfoAsFileSystemInfo()=dir.GetFileSystemInfos
InBlock.gif
InBlock.gif
'Countfolderandfiles
InBlock.gif
CountFiles(FSinfo)
InBlock.gif
InBlock.gif
'Savetotalfilescount
InBlock.gif
_totalFiles=_files
InBlock.gif
InBlock.gif
'Sendmessagetoclientform
InBlock.gif
CallClient(Thread.CurrentThread.Name,_files,_totalFiles,_directories,"END")
InBlock.gif
ExpandedSubBlockEnd.gif
EndSub

ExpandedSubBlockStart.gifContractedSubBlock.gif
PrivateSubReallyCopyFiles()SubReallyCopyFiles(ByValFSInfoAsFileSystemInfo())
InBlock.gif
'ChecktheFSInfoparameter.
InBlock.gif
IfFSInfoIsNothingThen
InBlock.gif
ThrowNewArgumentNullException("FSInfo")
InBlock.gif
EndIf
InBlock.gif
InBlock.gif
'Iteratethrougheachitem.
InBlock.gif
DimiAsFileSystemInfo
InBlock.gif
ForEachiInFSInfo
InBlock.gif
InBlock.gif
Try
InBlock.gif
'ChecktoseeifthisisaDirectoryInfoobject.
InBlock.gif
IfTypeOfiIsDirectoryInfoThen
InBlock.gif
'CasttheobjecttoaDirectoryInfoobject.
InBlock.gif
DimdInfoAsDirectoryInfo=CType(i,DirectoryInfo)
InBlock.gif
InBlock.gif
'Iterate(recurse)throughallsub-directories.
InBlock.gif
ReallyCopyFiles(dInfo.GetFileSystemInfos())
InBlock.gif
'ChecktoseeifthisisaFileInfoobject.
InBlock.gif
ElseIfTypeOfiIsFileInfoThen
InBlock.gif
'savethefullpathandfilename
InBlock.gif
_fileName=i.FullName
InBlock.gif
InBlock.gif
'Getthecopypathnameonly
InBlock.gif
DimcopypathAsString=ToPath&Mid(_fileName,Len(FromPath)+1,Len(_fileName)-Len(FromPath)-Len(i.Name))
InBlock.gif
InBlock.gif
'Createcopypathifitdoesnotexist
InBlock.gif
IfNotDirectory.Exists(copypath)Then
InBlock.gifDirectory.CreateDirectory(copypath)
InBlock.gif
EndIf
InBlock.gif
InBlock.gif
'Getthetopathandfilename
InBlock.gif
DimtofileAsString=ToPath&Mid(_fileName,Len(FromPath)+1)
InBlock.gif
InBlock.gif
'Updatestatusinfoonclient
InBlock.gif
DimfiAsNewFileInfo(_fileName)
InBlock.gif
DimMessageAsString=_fileName&"is"&Decimal.Round(CDec(fi.Length/1048576),2)&"MBinlength."
InBlock.gifCallClient(Thread.CurrentThread.Name,_copiedFiles,_totalFiles,_directories,Message)
InBlock.gif
InBlock.gif
'iffileexistscheckiffilehasbeenupdatedsincelastcopy
InBlock.gif
DimOkayToCopyAsBoolean=True
InBlock.gif
IfFile.Exists(tofile)Then
InBlock.gif
IfFile.GetLastWriteTime(_fileName)=File.GetLastWriteTime(tofile)Then
InBlock.gifOkayToCopy
=False
InBlock.gif
EndIf
InBlock.gif
EndIf
InBlock.gif
InBlock.gif
'Copyfilewithoverwrite
InBlock.gif
IfOkayToCopyThenFile.Copy(_fileName,tofile,True)
InBlock.gif
InBlock.gif
'Incrementcopiedfilecount
InBlock.gif
_copiedFiles+=1
InBlock.gif
InBlock.gif
EndIf
InBlock.gif
CatchexAsException
InBlock.gif
'Reporterrorbutcontinueprocessing
InBlock.gif
WriteLog(ERR_MSG&_fileName&vbCrLf&ex.Message.ToString)
InBlock.gif
EndTry
InBlock.gif
InBlock.gif
Nexti
InBlock.gif
ExpandedSubBlockEnd.gif
EndSub

ExpandedSubBlockStart.gifContractedSubBlock.gif
PrivateSubCountFiles()SubCountFiles(ByValFSInfoAsFileSystemInfo())
InBlock.gif
StaticShowCountAsLong=0
InBlock.gif
InBlock.gif
'ChecktheFSInfoparameter.
InBlock.gif
IfFSInfoIsNothingThen
InBlock.gif
ThrowNewArgumentNullException("FSInfo")
InBlock.gif
EndIf
InBlock.gif
InBlock.gif
'Iteratethrougheachitem.
InBlock.gif
DimiAsFileSystemInfo
InBlock.gif
ForEachiInFSInfo
InBlock.gif
InBlock.gif
Try
InBlock.gif
'ChecktoseeifthisisaDirectoryInfoobject.
InBlock.gif
IfTypeOfiIsDirectoryInfoThen
InBlock.gif
'Addonetothedirectorycount.
InBlock.gif
_directories+=1
InBlock.gif
InBlock.gif
'CasttheobjecttoaDirectoryInfoobject.
InBlock.gif
DimdInfoAsDirectoryInfo=CType(i,DirectoryInfo)
InBlock.gif
InBlock.gif
'Iterate(recurse)throughallsub-directories.
InBlock.gif
CountFiles(dInfo.GetFileSystemInfos())
InBlock.gif
'ChecktoseeifthisisaFileInfoobject.
InBlock.gif
ElseIfTypeOfiIsFileInfoThen
InBlock.gif
'Addonetothefilecount.
InBlock.gif
_files+=1
InBlock.gif
InBlock.gif
'displaycountforfirstfileineveryfolderthenevery200-forfasterperformance
InBlock.gif
SelectCaseShowCount
InBlock.gif
Case0
InBlock.gif
'Displaycount
InBlock.gif
CallClient(Thread.CurrentThread.Name,_files,_totalFiles,_directories,"")
InBlock.gif
CaseIs>=200
InBlock.gif
'Displaycount
InBlock.gif
CallClient(Thread.CurrentThread.Name,_files,_totalFiles,_directories,"")
InBlock.gif
InBlock.gif
'resetsodisplayisevery200filesinfolder
InBlock.gif
ShowCount=0
InBlock.gif
EndSelect
InBlock.gif
InBlock.gif
'Incrementshowcount
InBlock.gif
ShowCount+=1
InBlock.gif
InBlock.gif
EndIf
InBlock.gif
CatchexAsException
InBlock.gif
'Recorderrorthencontinue(likearesumenext)
InBlock.gif
WriteLog(ERR_MSG&_fileName&vbCrLf&ex.Message.ToString)
InBlock.gif
EndTry
InBlock.gif
InBlock.gif
Nexti
InBlock.gif
ExpandedSubBlockEnd.gif
EndSub

ExpandedSubBlockStart.gifContractedSubBlock.gif
PrivateSubCallClient()SubCallClient(ByValThreadNameAsString,ByValFilesAsLong,ByValTotalFilesAsLong,ByValDirectoriesAsLong,ByValMessageAsString)
InBlock.gif
InBlock.gif
SelectCaseThreadName
InBlock.gif
Case"Copy"
InBlock.gif
'Callthedelegatedmethod
InBlock.gif
_clientApp.Invoke(_callClientCopy,ThreadName,Files,Message)
InBlock.gif
Case"Count"
InBlock.gif
'Callthedelegatedmethod
InBlock.gif
_clientApp.Invoke(_callClientCount,ThreadName,Files,TotalFiles,Directories,Message)
InBlock.gif
EndSelect
InBlock.gif
InBlock.gif
'Letthethreadsleepbeforecontinuingsotheclientappwillhavetimetobeprocess(1millisecondisenough)
InBlock.gif
Thread.Sleep(0)
ExpandedSubBlockEnd.gif
EndSub

ExpandedSubBlockStart.gifContractedSubBlock.gif
PrivateSubOpenLog()SubOpenLog()
InBlock.gif
InBlock.gif
'Createlogfile
InBlock.gif
IfNotFile.Exists(StartDateTime&"-"&LOG_FILE)Then
InBlock.gif
Using_logFileAsStreamWriter=File.CreateText(LogFileName)
InBlock.gif_logFile.WriteLine(
"Logfilenameis:"&LogFileName)
InBlock.gif_logFile.WriteLine(
"BACKUPLOGFILESTARTEDAT:"&StartDateTime.ToString)
InBlock.gif_logFile.WriteLine(
"================================================")
InBlock.gif_logFile.Write(
"CopyingFROM:"&_fromPath)
InBlock.gif_logFile.WriteLine()
InBlock.gif_logFile.Write(
"CopyingTO:"&_toPath)
InBlock.gif_logFile.WriteLine()
InBlock.gif_logFile.Close()
InBlock.gif
EndUsing
InBlock.gif
EndIf
InBlock.gif
ExpandedSubBlockEnd.gif
EndSub

ExpandedSubBlockStart.gifContractedSubBlock.gif
PrivateSubWriteLog()SubWriteLog(ByValMessageAsString)
InBlock.gif
InBlock.gif
'CreateaninstanceofStreamWritertowritetexttoafile.
InBlock.gif
Using_logFileAsStreamWriter=File.AppendText(LogFileName)
InBlock.gif
'Addsometexttothefile.
InBlock.gif
_logFile.WriteLine()
InBlock.gif_logFile.WriteLine(
"TIMEOFLOGENTRY:"&DateTime.Now)
InBlock.gif
'Arbitraryobjectscanalsobewrittentothefile.
InBlock.gif
_logFile.WriteLine(Message)
InBlock.gif_logFile.Flush()
InBlock.gif_logFile.Close()
InBlock.gif
EndUsing
InBlock.gif
ExpandedSubBlockEnd.gif
EndSub

ExpandedSubBlockStart.gifContractedSubBlock.gif
PrivateSubCloseLog()SubCloseLog()
InBlock.gif
IfFile.Exists(LogFileName)Then_logFile.Close()
ExpandedSubBlockEnd.gif
EndSub

ExpandedSubBlockStart.gifContractedSubBlock.gif
PrivatePropertyFirstTime()PropertyFirstTime()AsBoolean
InBlock.gif
Get
InBlock.gif
Return_firstTime
InBlock.gif
EndGet
InBlock.gif
Set(ByValvalueAsBoolean)
InBlock.gif_firstTime
=value
InBlock.gif
EndSet
ExpandedSubBlockEnd.gif
EndProperty

ExpandedSubBlockStart.gifContractedSubBlock.gif
PublicPropertyFromPath()PropertyFromPath()AsString
InBlock.gif
Get
InBlock.gif
Return_fromPath
InBlock.gif
EndGet
InBlock.gif
Set(ByValvalueAsString)
InBlock.gif_fromPath
=value
InBlock.gif
EndSet
ExpandedSubBlockEnd.gif
EndProperty

ExpandedSubBlockStart.gifContractedSubBlock.gif
PublicPropertyToPath()PropertyToPath()AsString
InBlock.gif
Get
InBlock.gif
Return_toPath
InBlock.gif
EndGet
InBlock.gif
Set(ByValvalueAsString)
InBlock.gif_toPath
=value
InBlock.gif
EndSet
ExpandedSubBlockEnd.gif
EndProperty

ExpandedSubBlockStart.gifContractedSubBlock.gif
PublicPropertyStartDateTime()PropertyStartDateTime()AsDate
InBlock.gif
Get
InBlock.gif
Return_startDateTime
InBlock.gif
EndGet
InBlock.gif
Set(ByValvalueAsDate)
InBlock.gif_startDateTime
=value
InBlock.gif
EndSet
ExpandedSubBlockEnd.gif
EndProperty

ExpandedSubBlockStart.gifContractedSubBlock.gif
PublicReadOnlyPropertyLogFileName()PropertyLogFileName()AsString
InBlock.gif
Get
InBlock.gif
ReturnFormat(StartDateTime,"yyMMdd-hhmmss")&"-"&LOG_FILE
InBlock.gif
EndGet
ExpandedSubBlockEnd.gif
EndProperty

ExpandedSubBlockStart.gifContractedSubBlock.gif
PublicReadOnlyPropertyDirectories()PropertyDirectories()AsLong
InBlock.gif
Get
InBlock.gif
Return_directories
InBlock.gif
EndGet
ExpandedSubBlockEnd.gif
EndProperty

ExpandedSubBlockStart.gifContractedSubBlock.gif
PublicReadOnlyPropertyFiles()PropertyFiles()AsLong
InBlock.gif
Get
InBlock.gif
Return_files
InBlock.gif
EndGet
ExpandedSubBlockEnd.gif
EndProperty

ExpandedSubBlockStart.gifContractedSubBlock.gif
PublicReadOnlyPropertyTotalFiles()PropertyTotalFiles()AsLong
InBlock.gif
Get
InBlock.gif
Return_totalFiles
InBlock.gif
EndGet
ExpandedSubBlockEnd.gif
EndProperty

InBlock.gif
ExpandedBlockEnd.gif
EndClass

None.gif

作者的程序中还实现了一个比较有意思的特点,用户可以通过指定命令行参数进入后台命令行模式,而非界面模式,

Last Words

感谢作者的这篇文章,让我能参照他的思路用VC++实现了一个类似的多线程的文件备份工具。

Reference:

原文链接:Multithreading Backup Utility

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页