有没有人研究 文件拷贝....

MEFULEU 2013-03-21 05:30:20
使用delphi的函数拷贝似乎比fastcopy慢很多呀,使用线程更慢,不知道各位有什么好方法呢....

unit ReadWriteUnits;

{
拷贝文件
}

interface

uses
Windows,Classes,SysUtils,Messages,CopyHintUnits,Forms;

const WM_COPYEND_MSG = WM_USER + 1024;

type
pByte=array of byte;
pReadWriteInFo=^TReadWriteInfo;
TReadWriteInfo=record
ParentID:int64; //回送消息的父类句柄
Data:LongWord; //数据指针
Start:LongWord; //开始位置
len:LongWord; //拷贝数据长度
end;


TReadWriteFile = class(TThread)
private
{ Private declarations }
DataFile,DescF: HFile;
FWND:HWND;
FShowProgress:boolean;
FReadSum:int64;
Buf1,Buf2: array of byte;
FReadf,FWriteF:string;//读写的文件名称
pForm:TCopyHintForm;
iFileLength:int64; //文件的长度
ReadNumber,WriteNumber: LongWord;
ToReadLength:LongWord;
BuffFlag:boolean; //缓冲区标志,false使用buf1,true使用Buf2
ReadthreadCount:integer;
finfo1,finfo2:TReadWriteInfo;
Address1,address2:LongWord;
writethread1,writethread2:Tthread;
Handles:TWOHandleArray;
IsWritethread:boolean;
protected
procedure Execute; override;
procedure Openf;
procedure CLosef;
function CopyFile:boolean;
procedure ShowProgress;
procedure ResumWrite1;
procedure ResumWrite2;
procedure ExitPro;
public
constructor Create(MsgParent:HWND;const ReadFile,WriteFile:String;ShowProgress:boolean);
destructor Destroy;
end;

TWritethread=class(TThread)
private
Buf: pByte;
FDataFile:HFile;
FInfo:TReadWriteInfo;
protected
procedure Execute; override;
procedure WriteData;
procedure PostCopyEnd;
public
constructor Create(f:HFile;Info:TReadWriteInfo); //写文件的句柄和数据源结构
end;

implementation


{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

procedure TReadWriteFile.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }

constructor TWritethread.Create(f:HFile;Info:TReadWriteInfo); //写文件的句柄和数据源结构
begin
inherited Create(false);
FreeOnTerminate:=true;
FDataFile:=f;
FInfo:=Info;
end;

procedure TWritethread.Execute;
var
msg:TMSG;
begin
WriteData;

while (not Terminated) and GetMessage(msg,0,0,0) do //
begin
if msg.message=WM_USER then
begin
FInfo:=pReadWriteInFo(msg.wParam)^;
WriteData;
end;
//响应外部消息
TranslateMessage(msg);
DispatchMessage(msg);
end;

end;

procedure TWritethread.PostCopyEnd;
begin
//一次数据写完毕,返回消息
PostThreadMessage(FInfo.ParentID,WM_COPYEND_MSG,integer(@FInfo),integer(@Buf[0]));
end;

procedure TWritethread.WriteData;
var
WriteNumber:LongWord;
begin
Buf:=pByte(FInfo.data);
//设定写数据的位置
SetFilePointer(FDataFile,FInfo.Start, nil, FILE_BEGIN);
//存储流到文件
WriteFile(FDataFile,Buf[0], FInfo.len,WriteNumber,nil);

PostCopyEnd;

end;

{ TReadWriteFile }

constructor TReadWriteFile.Create(MsgParent:HWND;const ReadFile,WriteFile:String;ShowProgress:boolean);
begin
inherited Create(false);
FreeOnTerminate:=true;
FReadf:= ReadFile;
FWriteF:=WriteFile;
FShowProgress:=ShowProgress;
FWND:=MsgParent;
BuffFlag:=false;
pForm:=nil;
end;

destructor TReadWriteFile.Destroy;
begin

end;


procedure TReadWriteFile.CLosef;
begin
try
setlength(Buf1, 0);
setlength(Buf2, 0);
CloseHandle(DescF);
CloseHandle(DataFile);
if pForm <>nil then pForm.Free;
finally
if not self.Terminated then
PostMessage(FWND,WM_COPYEND_MSG,0,0);
end;
end;

procedure TReadWriteFile.Openf;
var
i,FHandle:integer;
begin

//获取源文件的长度
if not fileexists(FReadf) then
begin
exit;
end;
//打开文件源
DataFile := CreateFile(PChar(FReadf), GENERIC_READ,
0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if DataFile = 0 then
begin
exit;
end;

iFileLength := GetFileSize(DataFile, nil);
SetFilePointer(DataFile, 0, nil, FILE_BEGIN); //移动到文件开始

//创建需要存储的文件
DescF := CreateFile(PChar(FWriteF), GENERIC_WRITE,
0, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if DataFile = 0 then
begin
exit;
end;

//设定文件的长度
setfilepointer(DescF,iFileLength,nil,file_begin);
setendoffile(DescF);
SetFilePointer(DescF, 0, nil, FILE_BEGIN);

//(因为正常情况下,磁盘重复读取会导致很慢,所以这里只是开一个线程去读取文件)
FReadSum:=0;
ToReadLength:=10*1024*1024; //每次读取缓冲大小 //20m的缓冲区

setlength(Buf1,ToReadLength+1);
setlength(Buf2,ToReadLength+1);

if IsWritethread then
begin
finfo1.ParentID:=self.ThreadID;
finfo1.Data:=LongInt(@Buf1[0]);
finfo1.Start:=0;
finfo1.len:=0;
finfo2.ParentID:=self.ThreadID;
finfo2.Data:=LongInt(@Buf2[0]);
finfo2.Start:=0;
finfo2.len:=0;

Address1:= finfo1.Data;
Address2:= finfo2.Data;

for i:=0 to 1 do //复制数据到缓冲区
begin
if not CopyFile then break;
end;

//启动写数据线程
writethread1:=TWritethread.Create(DescF,finfo1);
writethread2:=TWritethread.Create(DescF,finfo2);

Handles[0]:=writethread1.Handle;
Handles[1]:=writethread2.Handle;
Sleep(100);
end else
begin
pForm:=TCopyHintForm.Create(Application);
pForm.ProgressBar1.Max:= iFileLength;
pForm.ProgressBar1.Position:=0;
while FReadSum < iFileLength do
begin
//读取数据
ReadFile(DataFile, Buf1[0], ToReadLength, ReadNumber, nil);

//重新确定一下读取的文件大小
FReadSum:=FReadSum + ReadNumber; //ReadNumber --为每次实际读取的文件大小

//存储流到文件
WriteFile(DescF, Buf1[0], ReadNumber, WriteNumber, nil);

ShowProgress;

if self.Terminated then break;
end;

pForm.Free;
pForm:=nil;
end;
end;

procedure TReadWriteFile.ShowProgress;
begin
if FShowProgress then
begin
pForm.ProgressBar1.Position:=FReadSum;
pForm.Show;
Application.ProcessMessages;
end;
end;

function TReadWriteFile.CopyFile:boolean;
begin
Result:=false;
//读取数据
if FReadSum < iFileLength then
begin
if BuffFlag then
begin
ReadFile(DataFile, Buf1[0], ToReadLength, ReadNumber, nil);
finfo1.Start:=FReadSum;
finfo1.len:=ReadNumber;
end else
begin
ReadFile(DataFile, Buf2[0], ToReadLength, ReadNumber, nil);
finfo2.Start:=FReadSum;
finfo2.len:=ReadNumber;
end;

//重新确定一下读取的文件大小
FReadSum:=FReadSum + ReadNumber; //ReadNumber --为每次实际读取的文件大小

//重新修改标志
BuffFlag:=not BuffFlag;

Result:=true;
end else
begin
Synchronize(ExitPro);
end;

end;

procedure TReadWriteFile.ExitPro;
begin
PostThreadMessage(self.ThreadID,WM_QUIT,0,0);
end;

procedure TReadWriteFile.ResumWrite1;
begin
PostThreadMessage(writethread1.ThreadID,WM_USER,integer(@finfo1),0);
end;

procedure TReadWriteFile.ResumWrite2;
begin
PostThreadMessage(writethread2.ThreadID,WM_USER,integer(@finfo2),0);
end;

procedure TReadWriteFile.Execute;
var
msg:TMSG;
tmpinfo:TReadWriteInfo;
begin
IsWritethread:=false; //测试标准,是否使用子线程写数据

if IsWritethread then //180m 耗时7s
begin
Openf; //打开和创建文件
while (not Terminated) and GetMessage(msg,0,0,0) do //
begin
if msg.message=WM_COPYEND_MSG then
begin
if msg.lParam = Address1 then
begin
BuffFlag:=true;
if CopyFile then
//重新激活复制子线程
ResumWrite1;
end else if msg.lParam = Address2 then
begin
BuffFlag:=false;
if CopyFile then
ResumWrite2;
end;
end;

//响应外部消息
TranslateMessage(msg);
DispatchMessage(msg);
end;

//等待线程结束
WaitForMultipleObjects(3, @Handles, True, INFINITE);

end else //单独读写过程 180m耗时 5s
Synchronize(Openf);

//关闭文件
Synchronize(CLosef);
end;

end.
...全文
378 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
山东蓝鸟贵薪 2013-03-22
  • 打赏
  • 举报
回复
不知,学习中、
MEFULEU 2013-03-22
  • 打赏
  • 举报
回复
弄了大半天 。。还是CopyFile 速度最快,瞧了瞧,fastcopy的源码,似乎是用copymemory...但是我调用它,速度还是跟不上...糊涂了
haitao 2013-03-22
  • 打赏
  • 举报
回复
xcopy /J 复制时不使用缓冲的 I/O。推荐复制大文件时使用。
haitao 2013-03-22
  • 打赏
  • 举报
回复
dos工具xcopy的速度如何?
MEFULEU 2013-03-22
  • 打赏
  • 举报
回复
CopyFile 拷贝大文件容易出现假死机情况,拷贝上边相同文件 耗时8s左右.. 而fastcopy 工具耗时大概4s.不到..,,...
MEFULEU 2013-03-22
  • 打赏
  • 举报
回复
我这个是7200转的硬盘,理论上可以达到60m以上吧.....所以 fastcopy的拷贝速度应该有80%以上了。 但是实际上,使用api拷贝,速度很低,所以 有些晕咧...
蓝色光芒 2013-03-22
  • 打赏
  • 举报
回复
TransRate= 43.32 MB/s 这个速度已经达到你硬盘速度极限的多少? 60%?
MEFULEU 2013-03-22
  • 打赏
  • 举报
回复
最为明显的,N多目录,文件同时拷贝时速度更快 ... fastcopy拷贝信息... TotalRead = 184.1 MB TotalWrite = 184.1 MB TotalFiles = 2 (0) TotalTime= 4.25 sec TransRate= 43.32 MB/s FileRate = 0.47 files/s
MEFULEU 2013-03-22
  • 打赏
  • 举报
回复
话说,网上的fastcopy工具,速度比微软的 拷贝快了 N 多,.
「已注销」 2013-03-22
  • 打赏
  • 举报
回复
自己去写文件纯属自找麻烦。 windows提供两个API: CopyFile, CopyFileEx 后者可以反馈实时进度。 难道自写的有微软谢的快?
UnkownState 2013-03-21
  • 打赏
  • 举报
回复
有没有使用win32 api copyfile试试。 createfile建立新文件的时候可以设置为不缓冲直接写,具体可以参考createfile的参数说明。

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧