BOOL ReadFileEx( HANDLE hFile, // handle of file to read LPVOID lpBuffer, // address of buffer DWORD nNumberOfBytesToRead, // number of bytes to read LPOVERLAPPED lpOverlapped, // address of offset LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // address of completion routine );在帮助里查到,好象是说这个函数是以overlapped的形式打开目的文件
uses Main, Question, Say, Display, FileOpen, CopyFile;Var ReadLock,WriteLock:TCriticalSection; PubInfo:PInfo=nil;{ Important: Methods and properties of objects in VCL or CLX can only be used in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure TCopyThread.UpdateCaption; begin Form1.Caption := 'Updated in a thread'; end; }{ TCopyThread }constructor TPartCopyThread.Create(sList: TStrings; sOutPath:String; sCopyForm:TForm; sCopySize, sCopyCount:Integer); Var i:Integer; begin Inherited Create(True); InfoList:=TList.Create; CopyCount:=sCopyCount; CopyForm:=TDForm(sCopyForm); List:=TStringList.Create; List.Text:=sList.Text; OutPath:=sOutPath; FreeOnTerminate:=True; CopySize:=sCopySize; OnTerminate:=OnClose; Qu:=mrNone; SetLength(Event,CopyCount); SetLength(HdArray,CopyCount); For i:=Low(Event) to High(Event) do begin Event[i]:=TSimpleEvent.Create; HdArray[i]:=Event[i].Handle; end; Resume; end;procedure TPartCopyThread.DoFinally; begin TDForm(CopyForm).Panel2.Caption:=Caption; TDForm(CopyForm).PageControl1.ActivePageIndex:=2; end;procedure TPartCopyThread.DoWriteList; begin TDForm(CopyForm).ListBox2.Items.Add(ErrorName); end;procedure TPartCopyThread.Execute; Var SourceBytes,i,j,Count,TimeStart,sCopySize,sCopyCount:Integer; sCount:Cardinal; Str,dStr:String; pTime:Integer; FileAttrib1,FileAttrib2:WIN32_FILE_ATTRIBUTE_DATA; OldErrMode:UINT; SourceHd,DescHd:THandle; Head:THeaderInfo; Info:PInfo; Sizees:DWORD; begin OldErrMode:=SetErrorMode(SEM_FailCriticalErrors); TimeStart:=GetTickCount; Try PostMessage(CopyForm.Handle,WM_SETMAXPROG1,List.Count,0); For i:=0 to List.Count-1 do begin DecCount:=CopyCount; if TDForm(CopyForm).Check or Terminated then Break; Try Try SourceName:=List.Strings[i]; if TDForm(CopyForm).RadioButton2.Checked then begin Str:=UpperCase(Trim(List.Strings[i])); dStr:=UpperCase(ExtractFileDrive(Str)); Str:=Copy(Str,Length(dStr)+2,Length(Str)); DescName:=OutPath+Str; Str:=ExtractFileDir(DescName); if DirectoryExists(Str)=False then if ForceDirectories(Str)=False then Continue; end else DescName:=OutPath+ExtractFileName(List.Strings[i]);
if FileExists(DescName) then begin SetLength(Param,2); Param[0]:='文件已经存在,是否覆盖?'; Param[1]:=DescName; ShowType:=stSimpleQuestion; Synchronize(ShowMesssageEx); if ShowMessageResult<>idyes then Continue; end; SourceHd:=CreateFile(PChar(SourceName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if SourceHd=0 then begin SetLength(Param,2); Param[0]:='文件打开失败,是否继续'; Param[1]:=SourceName; ShowType:=stSimpleQuestion; Synchronize(ShowMesssageEx); if ShowMessageResult=idyes then Continue else Break; end; if FileExists(DescName) then DeleteFile(DescName); DescHd:=CreateFile(PChar(DescName), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, 0); if DescHd=0 then begin SetLength(Param,2); Param[0]:='文件打开失败,是否继续'; Param[1]:=DescName; ShowType:=stSimpleQuestion; Synchronize(ShowMesssageEx); if ShowMessageResult=idyes then begin CloseHandle(SourceHd); Continue end else Break; end; Count:=GetFileSize(SourceHd,nil); if Count<=0 then begin CloseHandle(SourceHd); SourceHd:=0; CloseHandle(DescHd); DescHd:=0; Continue; end; SourceBytes:=Count div CopyCount; if SourceBytes=0 then sCopyCount:=1 else sCopyCount:=CopyCount; sCopySize:=Count mod CopyCount; PostMessage(CopyForm.Handle,WM_SETMAXPROG2,CopyCount,0); SetEvent(false); FreeInfos;
uses shellapi function copyTheFile(filename:string;Recycle:boolean):Integer; Var SHFileOpStruct:TSHFileOpStruct; begin Filename:=filename+#0#0; With SHFileOpStruct do begin Wnd := Application.Handle; wFunc := FO_copy; pFrom := pchar(Filename); pTo:= nil; fFlags := FOF_FILESONLY + FOF_NOCONFIRMATION + FOF_SILENT + FOF_NOERRORUI; if Recycle then fFlags:=fFlags + FOF_ALLOWUNDO end; Result:=SHFileOperation(SHFileOpStruct); End;
unit PartCopyThread; interface uses Classes, Windows, Types, SysUtils, Math, Controls, mmSystem, Forms, IdGlobal, SyncForm, Dialogs , RTLConsts, Syncobjs; type TCompletedRoutine=procedure (dwErr: DWORD; cbWritten: DWORD; pOVL: POVERLAPPED); stdcall; TPartCopyThread=class; PInfo = ^TInfo; TInfo = packed record Overlap: OVERLAPPED; CopySize:DWORD; FileSourceObj,FileDescObj: THandle; Thread:TPartCopyThread; IsWrite:Boolean; FileName:Array[0..1024] of Char; chBuf: PByte; Int:PInteger; Count,Start:Integer; Main:TForm; end; TPartCopyThread = class(TThread) private Qu,ShowMessageResult:TModalResult; List:TStrings; Error, Caption:String; Param:Array of String; ShowType:TShowType; SourceName,DescName,OutPath,ErrorName:String; CopyForm:TForm; CopySize:Integer; procedure DoWriteList; procedure ShowMesssageEx; procedure DoFinally; { Private declarations } protected procedure Execute; override; procedure OnClose(Sender:TObject); public CopyCount:Integer; DecCount:Integer; Events:TSimpleEvent; Constructor Create(sList:TStrings; sOutPath:String; sCopyForm:TForm; sCopySize, sCopyCount:Integer); end;implementationuses Main, Question, Say, Display, FileOpen, CopyFile, PartCopyThread_Ex; Var PubInfo:PInfo=nil; constructor TPartCopyThread.Create(sList: TStrings; sOutPath:String; sCopyForm:TForm; sCopySize, sCopyCount:Integer); Var i:Integer; begin Inherited Create(True); Events:=TSimpleEvent.Create; CopyCount:=sCopyCount; CopyForm:=TDForm(sCopyForm); List:=TStringList.Create; List.Text:=sList.Text; OutPath:=sOutPath; FreeOnTerminate:=True; CopySize:=sCopySize; OnTerminate:=OnClose; Qu:=mrNone; Resume; end;procedure TPartCopyThread.DoWriteList; begin TDForm(CopyForm).ListBox2.Items.Add(ErrorName); end;procedure TPartCopyThread.Execute; Var SourceBytes,i,j,k,Count,TimeStart,sCopySize,sCopyCount:Integer; sCount:Cardinal; Str,dStr:String; pTime:Integer; FileAttrib1,FileAttrib2:WIN32_FILE_ATTRIBUTE_DATA; OldErrMode:UINT; SourceHd,DescHd:THandle; Head:THeaderInfo; Info:PInfo; Sizees:DWORD; oConnect:OVERLAPPED; Tmp:Array[0..1] of Byte; PInt:PInteger; TmpCount:Integer; begin OldErrMode:=SetErrorMode(SEM_FailCriticalErrors); TimeStart:=GetTickCount; TmpCount:=20*1024*1024; Try PostMessage(CopyForm.Handle,WM_SETMAXPROG1,List.Count,0); For i:=0 to List.Count-1 do begin if TDForm(CopyForm).Check or Terminated then Break; Try Try SourceName:=List.Strings[i]; if TDForm(CopyForm).RadioButton2.Checked then begin Str:=UpperCase(Trim(List.Strings[i])); dStr:=UpperCase(ExtractFileDrive(Str)); Str:=Copy(Str,Length(dStr)+2,Length(Str)); DescName:=OutPath+Str; Str:=ExtractFileDir(DescName); if DirectoryExists(Str)=False then if ForceDirectories(Str)=False then Continue; end else DescName:=OutPath+ExtractFileName(List.Strings[i]); if FileExists(DescName) then begin SetLength(Param,2); Param[0]:='文件已经存在,是否覆盖?'; Param[1]:=DescName; ShowType:=stSimpleQuestion; Synchronize(ShowMesssageEx); if ShowMessageResult<>idyes then Continue; end; SourceHd:=CreateFile(PChar(SourceName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if SourceHd=0 then begin SetLength(Param,2); Param[0]:='文件打开失败,是否继续'; Param[1]:=SourceName; ShowType:=stSimpleQuestion; Synchronize(ShowMesssageEx); if ShowMessageResult=idyes then Continue else Break; end; if FileExists(DescName) then DeleteFile(DescName); DescHd:=CreateFile(PChar(DescName), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, 0);
if DescHd=0 then begin SetLength(Param,2); Param[0]:='文件打开失败,是否继续'; Param[1]:=DescName; ShowType:=stSimpleQuestion; Synchronize(ShowMesssageEx); if ShowMessageResult=idyes then begin CloseHandle(SourceHd); Continue end else Break; end; Count:=GetFileSize(SourceHd,nil); if Count=0 then begin Continue end; if (CopyCount=1) and (Count>TmpCount) then begin SourceBytes:=TmpCount; sCopyCount:=Count div SourceBytes; sCopySize:=Count-SourceBytes*sCopyCount; DecCount:=sCopyCount; end else begin SourceBytes:=Count div CopyCount; if SourceBytes=0 then sCopyCount:=1 else sCopyCount:=CopyCount; sCopySize:=Count mod CopyCount; if CopyCount<>1 then DecCount:=SCopyCount; if DecCount=1 then DecCount:=1; Events.ReSetEvent; end; PostMessage(CopyForm.Handle,WM_SETMAXPROG2,sCopyCount,0); For j:=0 to sCopyCount-1 do begin New(PubInfo); FillMemory(PubInfo,SizeOf(TInfo),0); StrPCopy(PubInfo^.FileName,SourceName); PubInfo^.Thread:=Self; PubInfo^.Overlap.Offset:=j*SourceBytes; if j=sCopyCount-1 then PubInfo^.CopySize:=SourceBytes+sCopySize else PubInfo^.CopySize:=SourceBytes; PubInfo^.chBuf:=AllocMem(PubInfo^.CopySize); PubInfo^.FileSourceObj:=SourceHd; PubInfo^.FileDescObj:=DescHd; PubInfo^.Main:=CopyForm; PubInfo^.Count:=j+1; PubInfo^.Start:=CopyCount; PubInfo^.Int:=PInt; if Not ReadFileEx(PubInfo^.FileSourceObj,PubInfo^.chBuf, PubInfo^.CopySize,@(PubInfo^.Overlap),@CompletedReadRoutine) then begin if GetLastError=997 then Continue; ShowMessage(IntToStr(GetLastError)); SetLength(Param,2); Param[0]:='读文件块'+IntToStr(j+1)+'失败,是否继续?'; Param[1]:=DescName; ShowType:=stSimpleQuestion; Synchronize(ShowMesssageEx); Dispose(PubInfo); if ShowMessageResult<>idyes then break else Continue; end else SleepEx(100,true); end; if CopyCount<>1 then begin While Events.WaitFor(100)<>wrSignaled do begin SleepEx(100,true); end; end; Except On E:Exception do begin ErrorName:=List.Strings[i]; Synchronize(DoWriteList); Continue; end; end; Finally if SourceHD<>0 then begin CloseHandle(SourceHD); SourceHd:=0; end; if DescHD<>0 then begin CloseHandle(DescHD); DescHd:=0; end; if CopyCount<>1 then PostMessage(CopyForm.Handle,WM_SETVALPROG1,i+1,0); end; end; if CopyCount=1 then begin While Events.WaitFor(100)<>wrSignaled do begin SleepEx(100,true) end; end; Finally pTime:=GetTickCount-TimeStart; dStr:=FloatToStr(pTime div (1000*60)); if TDForm(CopyForm).Check then Caption:='文件拷贝未完成!错误信息:'+Error else Caption:='文件拷贝完成!共花费时间:'+IntToStr(pTime div (1000*60))+'分'+FloatToStr(pTime mod (1000*60))+'毫秒'; Synchronize(DoFinally); SetErrorMode(OldErrMode); end; end;procedure TPartCopyThread.DoFinally; begin TDForm(CopyForm).Panel2.Caption:=Caption; TDForm(CopyForm).PageControl1.ActivePageIndex:=2; end;procedure TPartCopyThread.OnClose(Sender: TObject); Var i:Integer; begin Events.Free; TDForm(CopyForm).SpeedButton4.Caption:='开始文件拷贝'; TDForm(CopyForm).CheckBox3.Enabled:=true; end;procedure TPartCopyThread.ShowMesssageEx; begin ShowMessageResult:=SyncForm.ShowMessage(Param,ShowType); end;end.
unit Display;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Gauges, Buttons, StdCtrls, ExtCtrls, Menus, FileCtrl, Clipbrd, ShellApi, ComCtrls, CopyThread, XPMenu, ImgList, Mask, Syncobjs, IdGlobal, Spin, Math; Const WM_SETMAXPROG1=WM_USER+100; WM_SETMAXPROG2=WM_USER+101; WM_SETVALPROG1=WM_USER+102; WM_SETVALPROG2=WM_USER+103; WM_SETVALPROG2_2=WM_USER+104; WM_TEST=WM_USER+105; WM_COPYEND=WM_USER+106;procedure CompletedReadRoutine(dwErr: DWORD; cbBytesRead: DWORD; pOVL: POVERLAPPED); stdcall; procedure CompletedWriteRoutine(dwErr: DWORD; cbBytesRead: DWORD; pOVL: POVERLAPPED); stdcall;implementationuses PartCopyThread;Var ReadLock,WriteLock:TCriticalSection;procedure CompletedReadRoutine(dwErr: DWORD; cbBytesRead: DWORD; pOVL: POVERLAPPED); stdcall; var Info: PartCopyThread.PInfo; FWrite: Boolean; begin ReadLock.Acquire; Try Info:=PartCopyThread.PInfo(pOVL); if ((dwErr = 0) and (cbBytesRead <> 0)) then begin if Not Info^.IsWrite then begin pOVL^.hEvent:=Integer(Info); fWrite := WriteFileEx(Info^.FileDescObj, Info^.chBuf, cbBytesRead, pOVL^, @CompletedWriteRoutine); end end else begin if dwErr<>0 then begin TDForm(Info^.Main).ListBox2.Items.Add(Info^.FileName); end else if cbBytesRead=0 then begin end; end; Finally ReadLock.Release; end; end;procedure CompletedWriteRoutine(dwErr: DWORD; cbBytesRead: DWORD; pOVL: POVERLAPPED); stdcall; var Info: PartCopyThread.PInfo; FWrite: Boolean; begin WriteLock.Acquire; Try Try Info:=PartCopyThread.PInfo(Ptr(pOVL^.hEvent)); if ((dwErr = 0) and (cbBytesRead <> 0)) then begin Dec(Info^.Thread.DecCount); if Info^.Thread.DecCount<=0 then Info^.Thread.Events.SetEvent; end else begin if dwErr<>0 then begin TDForm(Info^.Main).ListBox2.Items.Add(Info^.FileName); end else if cbBytesRead=0 then begin end; end; //PostMessage(Info^.Main.Handle,WM_SETVALPROG2_2,0,0); //if Info^.Thread.CopyCount=1 then // PostMessage(Info^.Main.Handle,WM_SETVALPROG1,0,0); if Info^.Start=1 then PostMessage(Info^.Main.Handle,WM_SETVALPROG1,Info^.Count,0); PostMessage(Info^.Main.Handle,WM_SETVALPROG2_2,0,0); FreeMem(Info^.chBuf); Info^.Int:=nil; Dispose(Info); Except PostMessage(0,0,0,0); end; Finally WriteLock.Release; end; end;procedure TDForm.WMSETMAXPROG1(var Msg: TMessage); begin Gauge2.MaxValue:=Msg.WParam; Gauge2.Progress:=0; end;procedure TDForm.WMSETMAXPROG2(var Msg: TMessage); begin Gauge1.MaxValue:=Msg.WParam; Gauge1.Progress:=0; end;procedure TDForm.WMSETVALPROG1(var Msg: TMessage); begin Gauge2.Progress:=Gauge2.Progress+1; end;procedure TDForm.WMSETVALPROG2(var Msg: TMessage); begin Gauge1.Progress:=Msg.WParam; end;procedure TDForm.WMSETVALPROG2_2(var Msg: TMessage); begin Gauge1.Progress:=Gauge1.Progress+1; end;procedure TDForm.WMTEST(var Msg: TMessage); begin ShowMessage('ddddddddddddd'); end;procedure TDForm.WMCOPYEND(var Msg: TMessage); Var pTime:Integer; dStr:String; Info:PartCopyThread.PInfo; begin Info:=PartCopyThread.PInfo(Ptr(Msg.WParam)); pTime:=GetTickCount-Info^.Int^; dStr:=FloatToStr(RoundTo(pTime/(1000*60),-2)); Panel2.Caption:='文件拷贝完成!共花费时间:'+IntToStr(pTime div (1000*60))+'分'+Copy(dStr,Length(dStr)-1,2)+'秒'; PageControl1.ActivePageIndex:=2; Dispose(Info^.Int); Dispose(Info^.chBuf); Dispose(Info); end;Initialization ReadLock:=TCriticalSection.Create; WriteLock:=TCriticalSection.Create; Finalization ReadLock.Free; WriteLock.Free; end.这是使用READFILEEX、WRITEFILEEX的线程代码,在WINDOW2000下测试通过,当可使用的内存越大拷贝的速度越快,各位可以实验一下,这个恢复中的代码放在你的DEMO的主窗体里,窗体名称改为MAINFORM即可。
Repeat
BlockRead(f1, buf^, 65000, xfer);
BlockWrite(f2, buf^, xfer);
Until xfer < 65000;
Repeat
{BlockRead(f1, buf^, 65000, xfer);
BlockWrite(f2, buf^, xfer);}
或
FileStream:=TFileStream.Create('c:\a.dat',fmcreate);
fileStream.copyfrom(DescFileStream,DescFileStream.Size);
或
FileStream:=TFileStream.Create('c:\a.dat',fmcreate);
fileStream.copyfrom(DescFileStream,copysize);
COPYSIZE是分包拷贝的方法,可以拷贝大文件。
Until xfer < 65000;
但我说的是不使用这样的方法。
这是常规方法
如WIDNOWS下为4K,不知大家是否测试过LINUX下的文件拷贝,他的速度与内存的大小成正比,即内存越大速度越快。WINDOW下就不是,我的测试是在同一台机器,所以WINDOW自身的文件拷贝不可能快,需要另开思路。
LPVOID lpBuffer, // address of buffer
DWORD nNumberOfBytesToRead, // number of bytes to read
LPOVERLAPPED lpOverlapped, // address of offset
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // address of completion routine
);在帮助里查到,好象是说这个函数是以overlapped的形式打开目的文件
如果是linux文件的系统的话,可以自己写文件操作的系统调用,重新编译内核
windows只能利用现成的api构造算法,显然能力有限,最好能重写api
提升权限到ring0,在内存中划分一快足够大的空间,最好是比文件大
直接读取磁盘到内存
再从写入磁盘
这样读写次数比较少,应该会比较快吧有说错不要丢番茄啊~
要装xxcopy
unit PartCopyThread_NoEx;interfaceuses
Classes, Windows, Types, SysUtils, Math, Controls, mmSystem, Forms, IdGlobal, SyncForm, Dialogs
, RTLConsts, Syncobjs;
type
TCompletedRoutine=procedure (dwErr: DWORD; cbWritten: DWORD; pOVL: POVERLAPPED); stdcall;
TPartCopyThread=class;
PInfo = ^TInfo;
TInfo = packed record
Overlap: OVERLAPPED;
CopySize:DWORD;
FileSourceObj,FileDescObj: THandle;
Thread:TPartCopyThread;
IsWrite:Boolean;
FileName:Array[0..1024] of Char;
chBuf: PByte;
end; TFileStreamEx=Class(THandleStream)
private
function FileCreatev(const FileName: string): Integer;
function FileOpenv(const FileName: string; Mode: LongWord): Integer;
function FileReadv(Handle: Integer; var Buffer; Count: LongWord; ReadInfo:OVERLAPPED; ProcObj:Pointer): Integer;
function FileWritev(Handle: Integer; const Buffer; Count: LongWord; WriteInfo:OVERLAPPED; ProcObj:Pointer): Integer;
public
Constructor Create(FileName:String; CreateMode:DWORD);
end; TPartCopyThread = class(TThread)
private
Qu,ShowMessageResult:TModalResult;
List:TStrings;
Error:String;
InfoList:TList;
Param:Array of String;
ShowType:TShowType;
SourceName,DescName,OutPath,Caption,CurStr,OldStr,ErrorName:String;
CopyForm:TForm;
CopySize:Integer;
TmpSize:Integer;
DescCurPos:Integer;
ProcObj:TCompletedRoutine;
CopyCount,DecCount:Integer;
Event:Array of TSimpleEvent;
HdArray:Array of THandle;
procedure ShowSize;
procedure DoWriteList;
procedure DoFinally;
procedure ShowMesssageEx;
procedure SetEvent(Enabled:Boolean);
procedure FreeInfos; { Private declarations }
protected
procedure Execute; override;
procedure OnClose(Sender:TObject);
public
Constructor Create(sList:TStrings; sOutPath:String; sCopyForm:TForm; sCopySize, sCopyCount:Integer);
end;implementation
ReadLock,WriteLock:TCriticalSection;
PubInfo:PInfo=nil;{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure TCopyThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }{ TCopyThread }constructor TPartCopyThread.Create(sList: TStrings; sOutPath:String; sCopyForm:TForm; sCopySize, sCopyCount:Integer);
Var
i:Integer;
begin
Inherited Create(True);
InfoList:=TList.Create;
CopyCount:=sCopyCount;
CopyForm:=TDForm(sCopyForm);
List:=TStringList.Create;
List.Text:=sList.Text;
OutPath:=sOutPath;
FreeOnTerminate:=True;
CopySize:=sCopySize;
OnTerminate:=OnClose;
Qu:=mrNone;
SetLength(Event,CopyCount);
SetLength(HdArray,CopyCount);
For i:=Low(Event) to High(Event) do
begin
Event[i]:=TSimpleEvent.Create;
HdArray[i]:=Event[i].Handle;
end;
Resume;
end;procedure TPartCopyThread.DoFinally;
begin
TDForm(CopyForm).Panel2.Caption:=Caption;
TDForm(CopyForm).PageControl1.ActivePageIndex:=2;
end;procedure TPartCopyThread.DoWriteList;
begin
TDForm(CopyForm).ListBox2.Items.Add(ErrorName);
end;procedure TPartCopyThread.Execute;
Var
SourceBytes,i,j,Count,TimeStart,sCopySize,sCopyCount:Integer;
sCount:Cardinal;
Str,dStr:String;
pTime:Integer;
FileAttrib1,FileAttrib2:WIN32_FILE_ATTRIBUTE_DATA;
OldErrMode:UINT;
SourceHd,DescHd:THandle;
Head:THeaderInfo;
Info:PInfo;
Sizees:DWORD;
begin
OldErrMode:=SetErrorMode(SEM_FailCriticalErrors);
TimeStart:=GetTickCount;
Try
PostMessage(CopyForm.Handle,WM_SETMAXPROG1,List.Count,0);
For i:=0 to List.Count-1 do
begin
DecCount:=CopyCount;
if TDForm(CopyForm).Check or Terminated then
Break;
Try
Try
SourceName:=List.Strings[i];
if TDForm(CopyForm).RadioButton2.Checked then
begin
Str:=UpperCase(Trim(List.Strings[i]));
dStr:=UpperCase(ExtractFileDrive(Str));
Str:=Copy(Str,Length(dStr)+2,Length(Str));
DescName:=OutPath+Str;
Str:=ExtractFileDir(DescName);
if DirectoryExists(Str)=False then
if ForceDirectories(Str)=False then
Continue;
end
else
DescName:=OutPath+ExtractFileName(List.Strings[i]);
begin
SetLength(Param,2);
Param[0]:='文件已经存在,是否覆盖?';
Param[1]:=DescName;
ShowType:=stSimpleQuestion;
Synchronize(ShowMesssageEx);
if ShowMessageResult<>idyes then
Continue;
end;
SourceHd:=CreateFile(PChar(SourceName), GENERIC_READ,
FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if SourceHd=0 then
begin
SetLength(Param,2);
Param[0]:='文件打开失败,是否继续';
Param[1]:=SourceName;
ShowType:=stSimpleQuestion;
Synchronize(ShowMesssageEx);
if ShowMessageResult=idyes then
Continue
else
Break;
end;
if FileExists(DescName) then
DeleteFile(DescName);
DescHd:=CreateFile(PChar(DescName), GENERIC_WRITE,
FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, 0);
if DescHd=0 then
begin
SetLength(Param,2);
Param[0]:='文件打开失败,是否继续';
Param[1]:=DescName;
ShowType:=stSimpleQuestion;
Synchronize(ShowMesssageEx);
if ShowMessageResult=idyes then
begin
CloseHandle(SourceHd);
Continue
end
else
Break;
end;
Count:=GetFileSize(SourceHd,nil);
if Count<=0 then
begin
CloseHandle(SourceHd);
SourceHd:=0;
CloseHandle(DescHd);
DescHd:=0;
Continue;
end;
SourceBytes:=Count div CopyCount;
if SourceBytes=0 then
sCopyCount:=1
else
sCopyCount:=CopyCount;
sCopySize:=Count mod CopyCount;
PostMessage(CopyForm.Handle,WM_SETMAXPROG2,CopyCount,0);
SetEvent(false);
FreeInfos;
function copyTheFile(filename:string;Recycle:boolean):Integer;
Var SHFileOpStruct:TSHFileOpStruct;
begin
Filename:=filename+#0#0;
With SHFileOpStruct do
begin
Wnd := Application.Handle;
wFunc := FO_copy;
pFrom := pchar(Filename);
pTo:= nil;
fFlags := FOF_FILESONLY + FOF_NOCONFIRMATION + FOF_SILENT + FOF_NOERRORUI;
if Recycle then fFlags:=fFlags + FOF_ALLOWUNDO
end;
Result:=SHFileOperation(SHFileOpStruct);
End;
interface
uses
Classes, Windows, Types, SysUtils, Math, Controls, mmSystem, Forms, IdGlobal, SyncForm, Dialogs
, RTLConsts, Syncobjs;
type
TCompletedRoutine=procedure (dwErr: DWORD; cbWritten: DWORD; pOVL: POVERLAPPED); stdcall;
TPartCopyThread=class;
PInfo = ^TInfo;
TInfo = packed record
Overlap: OVERLAPPED;
CopySize:DWORD;
FileSourceObj,FileDescObj: THandle;
Thread:TPartCopyThread;
IsWrite:Boolean;
FileName:Array[0..1024] of Char;
chBuf: PByte;
Int:PInteger;
Count,Start:Integer;
Main:TForm;
end; TPartCopyThread = class(TThread)
private
Qu,ShowMessageResult:TModalResult;
List:TStrings;
Error, Caption:String;
Param:Array of String;
ShowType:TShowType;
SourceName,DescName,OutPath,ErrorName:String;
CopyForm:TForm;
CopySize:Integer;
procedure DoWriteList;
procedure ShowMesssageEx;
procedure DoFinally; { Private declarations }
protected
procedure Execute; override;
procedure OnClose(Sender:TObject);
public
CopyCount:Integer;
DecCount:Integer;
Events:TSimpleEvent;
Constructor Create(sList:TStrings; sOutPath:String; sCopyForm:TForm; sCopySize, sCopyCount:Integer);
end;implementationuses Main, Question, Say, Display, FileOpen, CopyFile, PartCopyThread_Ex;
Var
PubInfo:PInfo=nil;
constructor TPartCopyThread.Create(sList: TStrings; sOutPath:String; sCopyForm:TForm; sCopySize, sCopyCount:Integer);
Var
i:Integer;
begin
Inherited Create(True);
Events:=TSimpleEvent.Create;
CopyCount:=sCopyCount;
CopyForm:=TDForm(sCopyForm);
List:=TStringList.Create;
List.Text:=sList.Text;
OutPath:=sOutPath;
FreeOnTerminate:=True;
CopySize:=sCopySize;
OnTerminate:=OnClose;
Qu:=mrNone;
Resume;
end;procedure TPartCopyThread.DoWriteList;
begin
TDForm(CopyForm).ListBox2.Items.Add(ErrorName);
end;procedure TPartCopyThread.Execute;
Var
SourceBytes,i,j,k,Count,TimeStart,sCopySize,sCopyCount:Integer;
sCount:Cardinal;
Str,dStr:String;
pTime:Integer;
FileAttrib1,FileAttrib2:WIN32_FILE_ATTRIBUTE_DATA;
OldErrMode:UINT;
SourceHd,DescHd:THandle;
Head:THeaderInfo;
Info:PInfo;
Sizees:DWORD;
oConnect:OVERLAPPED;
Tmp:Array[0..1] of Byte;
PInt:PInteger;
TmpCount:Integer;
begin
OldErrMode:=SetErrorMode(SEM_FailCriticalErrors);
TimeStart:=GetTickCount;
TmpCount:=20*1024*1024;
Try
PostMessage(CopyForm.Handle,WM_SETMAXPROG1,List.Count,0);
For i:=0 to List.Count-1 do
begin
if TDForm(CopyForm).Check or Terminated then
Break;
Try
Try
SourceName:=List.Strings[i];
if TDForm(CopyForm).RadioButton2.Checked then
begin
Str:=UpperCase(Trim(List.Strings[i]));
dStr:=UpperCase(ExtractFileDrive(Str));
Str:=Copy(Str,Length(dStr)+2,Length(Str));
DescName:=OutPath+Str;
Str:=ExtractFileDir(DescName);
if DirectoryExists(Str)=False then
if ForceDirectories(Str)=False then
Continue;
end
else
DescName:=OutPath+ExtractFileName(List.Strings[i]);
if FileExists(DescName) then
begin
SetLength(Param,2);
Param[0]:='文件已经存在,是否覆盖?';
Param[1]:=DescName;
ShowType:=stSimpleQuestion;
Synchronize(ShowMesssageEx);
if ShowMessageResult<>idyes then
Continue;
end;
SourceHd:=CreateFile(PChar(SourceName), GENERIC_READ,
FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if SourceHd=0 then
begin
SetLength(Param,2);
Param[0]:='文件打开失败,是否继续';
Param[1]:=SourceName;
ShowType:=stSimpleQuestion;
Synchronize(ShowMesssageEx);
if ShowMessageResult=idyes then
Continue
else
Break;
end;
if FileExists(DescName) then
DeleteFile(DescName);
DescHd:=CreateFile(PChar(DescName), GENERIC_WRITE,
FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, 0);
begin
SetLength(Param,2);
Param[0]:='文件打开失败,是否继续';
Param[1]:=DescName;
ShowType:=stSimpleQuestion;
Synchronize(ShowMesssageEx);
if ShowMessageResult=idyes then
begin
CloseHandle(SourceHd);
Continue
end
else
Break;
end;
Count:=GetFileSize(SourceHd,nil);
if Count=0 then
begin
Continue
end;
if (CopyCount=1) and (Count>TmpCount) then
begin
SourceBytes:=TmpCount;
sCopyCount:=Count div SourceBytes;
sCopySize:=Count-SourceBytes*sCopyCount;
DecCount:=sCopyCount;
end
else
begin
SourceBytes:=Count div CopyCount;
if SourceBytes=0 then
sCopyCount:=1
else
sCopyCount:=CopyCount;
sCopySize:=Count mod CopyCount;
if CopyCount<>1 then
DecCount:=SCopyCount;
if DecCount=1 then
DecCount:=1;
Events.ReSetEvent;
end;
PostMessage(CopyForm.Handle,WM_SETMAXPROG2,sCopyCount,0);
For j:=0 to sCopyCount-1 do
begin
New(PubInfo);
FillMemory(PubInfo,SizeOf(TInfo),0);
StrPCopy(PubInfo^.FileName,SourceName);
PubInfo^.Thread:=Self;
PubInfo^.Overlap.Offset:=j*SourceBytes;
if j=sCopyCount-1 then
PubInfo^.CopySize:=SourceBytes+sCopySize
else
PubInfo^.CopySize:=SourceBytes;
PubInfo^.chBuf:=AllocMem(PubInfo^.CopySize);
PubInfo^.FileSourceObj:=SourceHd;
PubInfo^.FileDescObj:=DescHd;
PubInfo^.Main:=CopyForm;
PubInfo^.Count:=j+1;
PubInfo^.Start:=CopyCount;
PubInfo^.Int:=PInt; if Not ReadFileEx(PubInfo^.FileSourceObj,PubInfo^.chBuf,
PubInfo^.CopySize,@(PubInfo^.Overlap),@CompletedReadRoutine) then
begin
if GetLastError=997 then
Continue;
ShowMessage(IntToStr(GetLastError));
SetLength(Param,2);
Param[0]:='读文件块'+IntToStr(j+1)+'失败,是否继续?';
Param[1]:=DescName;
ShowType:=stSimpleQuestion;
Synchronize(ShowMesssageEx);
Dispose(PubInfo);
if ShowMessageResult<>idyes then
break
else
Continue;
end
else
SleepEx(100,true);
end;
if CopyCount<>1 then
begin
While Events.WaitFor(100)<>wrSignaled do
begin
SleepEx(100,true);
end;
end; Except
On E:Exception do
begin
ErrorName:=List.Strings[i];
Synchronize(DoWriteList);
Continue;
end;
end;
Finally
if SourceHD<>0 then
begin
CloseHandle(SourceHD);
SourceHd:=0;
end;
if DescHD<>0 then
begin
CloseHandle(DescHD);
DescHd:=0;
end;
if CopyCount<>1 then
PostMessage(CopyForm.Handle,WM_SETVALPROG1,i+1,0);
end;
end;
if CopyCount=1 then
begin
While Events.WaitFor(100)<>wrSignaled do
begin
SleepEx(100,true)
end;
end;
Finally
pTime:=GetTickCount-TimeStart;
dStr:=FloatToStr(pTime div (1000*60));
if TDForm(CopyForm).Check then
Caption:='文件拷贝未完成!错误信息:'+Error
else
Caption:='文件拷贝完成!共花费时间:'+IntToStr(pTime div (1000*60))+'分'+FloatToStr(pTime mod (1000*60))+'毫秒';
Synchronize(DoFinally);
SetErrorMode(OldErrMode);
end;
end;procedure TPartCopyThread.DoFinally;
begin
TDForm(CopyForm).Panel2.Caption:=Caption;
TDForm(CopyForm).PageControl1.ActivePageIndex:=2;
end;procedure TPartCopyThread.OnClose(Sender: TObject);
Var
i:Integer;
begin
Events.Free;
TDForm(CopyForm).SpeedButton4.Caption:='开始文件拷贝';
TDForm(CopyForm).CheckBox3.Enabled:=true;
end;procedure TPartCopyThread.ShowMesssageEx;
begin
ShowMessageResult:=SyncForm.ShowMessage(Param,ShowType);
end;end.
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Gauges, Buttons, StdCtrls, ExtCtrls, Menus, FileCtrl, Clipbrd, ShellApi,
ComCtrls, CopyThread, XPMenu, ImgList, Mask, Syncobjs, IdGlobal, Spin, Math;
Const
WM_SETMAXPROG1=WM_USER+100;
WM_SETMAXPROG2=WM_USER+101;
WM_SETVALPROG1=WM_USER+102;
WM_SETVALPROG2=WM_USER+103;
WM_SETVALPROG2_2=WM_USER+104;
WM_TEST=WM_USER+105;
WM_COPYEND=WM_USER+106;procedure CompletedReadRoutine(dwErr: DWORD; cbBytesRead: DWORD; pOVL: POVERLAPPED); stdcall;
procedure CompletedWriteRoutine(dwErr: DWORD; cbBytesRead: DWORD; pOVL: POVERLAPPED); stdcall;implementationuses PartCopyThread;Var
ReadLock,WriteLock:TCriticalSection;procedure CompletedReadRoutine(dwErr: DWORD; cbBytesRead: DWORD; pOVL: POVERLAPPED); stdcall;
var
Info: PartCopyThread.PInfo;
FWrite: Boolean;
begin
ReadLock.Acquire;
Try
Info:=PartCopyThread.PInfo(pOVL);
if ((dwErr = 0) and (cbBytesRead <> 0)) then
begin
if Not Info^.IsWrite then
begin
pOVL^.hEvent:=Integer(Info);
fWrite := WriteFileEx(Info^.FileDescObj,
Info^.chBuf,
cbBytesRead,
pOVL^,
@CompletedWriteRoutine);
end
end
else
begin
if dwErr<>0 then
begin
TDForm(Info^.Main).ListBox2.Items.Add(Info^.FileName);
end
else if cbBytesRead=0 then
begin
end;
end;
Finally
ReadLock.Release;
end;
end;procedure CompletedWriteRoutine(dwErr: DWORD; cbBytesRead: DWORD; pOVL: POVERLAPPED); stdcall;
var
Info: PartCopyThread.PInfo;
FWrite: Boolean;
begin
WriteLock.Acquire;
Try
Try
Info:=PartCopyThread.PInfo(Ptr(pOVL^.hEvent));
if ((dwErr = 0) and (cbBytesRead <> 0)) then
begin
Dec(Info^.Thread.DecCount);
if Info^.Thread.DecCount<=0 then
Info^.Thread.Events.SetEvent;
end
else
begin
if dwErr<>0 then
begin
TDForm(Info^.Main).ListBox2.Items.Add(Info^.FileName);
end
else if cbBytesRead=0 then
begin
end;
end;
//PostMessage(Info^.Main.Handle,WM_SETVALPROG2_2,0,0);
//if Info^.Thread.CopyCount=1 then
// PostMessage(Info^.Main.Handle,WM_SETVALPROG1,0,0);
if Info^.Start=1 then
PostMessage(Info^.Main.Handle,WM_SETVALPROG1,Info^.Count,0);
PostMessage(Info^.Main.Handle,WM_SETVALPROG2_2,0,0);
FreeMem(Info^.chBuf);
Info^.Int:=nil;
Dispose(Info);
Except
PostMessage(0,0,0,0);
end;
Finally
WriteLock.Release;
end;
end;procedure TDForm.WMSETMAXPROG1(var Msg: TMessage);
begin
Gauge2.MaxValue:=Msg.WParam;
Gauge2.Progress:=0;
end;procedure TDForm.WMSETMAXPROG2(var Msg: TMessage);
begin
Gauge1.MaxValue:=Msg.WParam;
Gauge1.Progress:=0;
end;procedure TDForm.WMSETVALPROG1(var Msg: TMessage);
begin
Gauge2.Progress:=Gauge2.Progress+1;
end;procedure TDForm.WMSETVALPROG2(var Msg: TMessage);
begin
Gauge1.Progress:=Msg.WParam;
end;procedure TDForm.WMSETVALPROG2_2(var Msg: TMessage);
begin
Gauge1.Progress:=Gauge1.Progress+1;
end;procedure TDForm.WMTEST(var Msg: TMessage);
begin
ShowMessage('ddddddddddddd');
end;procedure TDForm.WMCOPYEND(var Msg: TMessage);
Var
pTime:Integer;
dStr:String;
Info:PartCopyThread.PInfo;
begin
Info:=PartCopyThread.PInfo(Ptr(Msg.WParam));
pTime:=GetTickCount-Info^.Int^;
dStr:=FloatToStr(RoundTo(pTime/(1000*60),-2));
Panel2.Caption:='文件拷贝完成!共花费时间:'+IntToStr(pTime div (1000*60))+'分'+Copy(dStr,Length(dStr)-1,2)+'秒';
PageControl1.ActivePageIndex:=2;
Dispose(Info^.Int);
Dispose(Info^.chBuf);
Dispose(Info);
end;Initialization
ReadLock:=TCriticalSection.Create;
WriteLock:=TCriticalSection.Create;
Finalization
ReadLock.Free;
WriteLock.Free;
end.这是使用READFILEEX、WRITEFILEEX的线程代码,在WINDOW2000下测试通过,当可使用的内存越大拷贝的速度越快,各位可以实验一下,这个恢复中的代码放在你的DEMO的主窗体里,窗体名称改为MAINFORM即可。