unit Utest; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls; const _i32MB=32*1024*1024 ; type TForm1 = class(TForm) LabelSrc: TLabel; EditSrc: TEdit; LabelTar: TLabel; EditTar: TEdit; btnCopy: TButton; ProgressBarByNum: TProgressBar; ProgressBarBySize: TProgressBar; procedure btnCopyClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } iNumofFiles : integer ; // 記錄目錄下檔案總數 i64SizeofFiles : int64 ; // 記錄目錄下檔案大小總和 pBuf : pointer ; function DoCopyFile(sSrcFile,sTarFile:string;iLeftNum:integer;var i64LeftSize:int64):boolean ; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} var slSrcFiles : TStringList ; // 輸入: 要查詢的路徑(要含 *.*) , 要存放檔案大小總和的變數(用 int64避免4GB問題) // 傳回值: 檔案總數 // 檔案列表會存放到 slSrcFiles 中, 此物件需在外部宣告 function TravelTree(sRoot:string; var i64TotalSize:int64):integer ; var fd : WIN32_FIND_DATA ; h : Thandle ; sPath, sName : string ; begin result:=0 ; h:=findfirstfile(pchar(sRoot),FD) ; if h=INVALID_HANDLE_VALUE then exit ; sPath:=ExtractFilePath(sRoot) ; repeat sName:=strpas(fd.cFilename) ; if (fd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY)=FILE_ATTRIBUTE_DIRECTORY then begin // 若是目錄則用 recursive if (sName<>'.') and (sName<>'..') then result:=result+TravelTree(sPath+sName+'\*.*',i64totalSize) ; end else begin result:=result+1 ; slSrcFiles.Add(sPath+sName) ; if fd.nFileSizeHigh=0 then i64TotalSize:=i64TotalSize+fd.nFileSizeLow else i64TotalSize:=i64TotalSize+(int64(fd.nFileSizeHigh)shl 32)+fd.nFileSizeLow ; end ; until FindNextFile(h,fd)=false ; windows.FindClose(h) ; end ; function TForm1.DoCopyFile(sSrcFile,sTarFile:string;iLeftNum:integer;var i64LeftSize:int64):boolean ; var fsSrc, fsTar : TFileStream ; sPath : string ; iReadSize : integer ; begin sPath:=extractFilePath(sTarFile) ; if not directoryExists(sPath) then forceDirectories(sPath) ; result:=true ; try fsSrc:=TFileStream.Create(sSrcFile,fmOpenRead); fsTar:=TFileStream.Create(sTarFile,fmCreate); try repeat iReadSize:=fsSrc.Read(pBuf^,_i32MB) ; fsTar.Write(pBuf^,iReadSize) ; i64LeftSize:=i64LeftSize-iReadSize ; // 更新 大小 的進度列 progressBarBySize.Position:=round((i64SizeOfFiles-i64LeftSize)/i64SizeOfFiles*100) ; // 處理訊息, 例如中斷執行 application.ProcessMessages ; until iReadSize<_i32MB ; finally fsSrc.Free ; fsTar.Free ; end ; // 更新 個數 的進度列 progressBarByNum.Position:=round((iNumOfFiles-iLeftNum)/iNumOfFiles*100) ; except result:=false ; end ; end ; procedure TForm1.btnCopyClick(Sender: TObject); var i64Size: int64 ; sTarPath, sTarFile, sSrcFile : string ; iSrcLen : integer ; i : integer ; begin i64Size:=0 ; slSrcFiles:=TStringList.Create ; try // 計算目錄下的檔案總數及檔案大小總和 iNumofFiles:=TravelTree(EditSrc.Text+'\*.*',i64Size) ; i64SizeOfFiles:=i64Size ; // 進度列用 百分比 計算 progressbarByNum.Max:=100 ; progressbarBySize.Max:=100 ; progressbarByNum.Position:=0 ; progressbarBySize.Position:=0 ; i:=slSrcFiles.Count-1 ; iSrcLen:=length(editSrc.text)+1 ; sTarPath:=editTar.text ; if not directoryExists(sTarPath) then forceDirectories(sTarPath) ; while i>=0 do begin // 來源檔名 sSrcFile:=slSrcFiles[i] ; // 目的檔名 sTarFile:=sTarPath+copy(sSrcFile,iSrcLen,maxint) ; // 複製每一個檔案 DoCopyFile(sSrcFile,sTarFile, i, i64Size) ; dec(i) ; end ; finally slSrcFiles.Free ; end ; end; procedure TForm1.FormCreate(Sender: TObject); begin getmem(pBuf,_i32MB) ; end; procedure TForm1.FormDestroy(Sender: TObject); begin freemem(pBuf,_i32MB) ; end; end. |
2010年2月18日 星期四
程式技巧(Delphi) - 包含子目錄的檔案複製 ( 有 檔案個數 及 檔案大小 2個進度列)
這個程式是拿來當範例用的, 還有許多地方可以加強, 例如對目的檔案的日期、屬性等訊息並未複製, 只有檔案內容的複製. 未處理 unicode 檔案, 未檢查空間是否足夠, 未用多執行緒加速...等. 不過已可達到 複製包含子目錄下的檔案, 並顯示進度列這 2 個基本需求
訂閱:
張貼留言 (Atom)
谢谢老师
回覆刪除