如何实现文件的快速复制?(50分)

  • 主题发起人 主题发起人 hxy2002
  • 开始时间 开始时间
H

hxy2002

Unregistered / Unconfirmed
GUEST, unregistred user!
如何实现文件的快速复制?
用一个线程读,一个线程写,这样的想法可行吗?
 
看是怎么用了,也可以用CopyFile,这是API,这个方法就是系统文件拷贝
 
CopyFile(pchar(strfrom), pchar(strto), (false or true));
 
就是自己写的,不想用系统的api
createfile
readfile
writefile
closefile
这样有什么办法可以提高速度吗?
 
文件内核对象
32位 API 提供一个称为文件映像的特性,它允许将文件直接映射为一个应用的虚拟内存空间,这一技术可用于简化和加速文件访问。
CreateFileMapping
创建和命名映射
MapViewOfFile
把文件映射装载如内存
UnmapViewOfFile
释放视图并把变化写回文件
FlushViewOfFile
将视图的变化刷新写入磁盘
用以上几个常用的 API 函数,能快速的提高文件操作过程函数的编写吗?
 
理解错了,不好意思
 
TO:Highpeak
能说清楚一点吗?
 
我有一个同时拷贝文件的例子,要的话就留个EMAIL吧
 
打开文件,然后每次读取一个筷,比如8092字节!然后写入另外一个文件!
采用blockread
下面是borland help
var

FromF, ToF: file;
NumRead, NumWritten: Integer;
Buf: array[1..2048] of Char;
begin

if OpenDialog1.Execute then
{ Display Open dialog box }
begin

AssignFile(FromF, OpenDialog1.FileName);
Reset(FromF, 1); { Record size = 1 }
if SaveDialog1.Execute then
{ Display Save dialog box}
begin

AssignFile(ToF, SaveDialog1.FileName); { Open output file }

Rewrite(ToF, 1); { Record size = 1 }
Canvas.TextOut(10, 10, 'Copying ' + IntToStr(FileSize(FromF))
+ ' bytes...');
repeat
BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
BlockWrite(ToF, Buf, NumRead, NumWritten);
until (NumRead = 0) or (NumWritten <> NumRead);
CloseFile(FromF);
CloseFile(ToF);
end;

end;

end;
 
TO:app2001
gxfzdyj@sina.com
同时拷文件,是用多线程吧。
我的想法是如何提高拷单个文件的速度。
 
To:dcsdcs
如果加大块的大小长度,会不会加快文件读写的速度。
我有一个想法是把blockread放在一个线程
blockwrite放在另外一个线程
先读取一段数据到一个缓冲区,然后启动写线程写入另外一个文件。
同时读线程也在同步读。
这样读和写就是同步进行了。
不知,这样可不可以,提高速度。

大家看了,提一提意见。
 
多线程复制文件的源码
unit U_CopyThread;

interface

uses
Windows, Messages, SysUtils, Classes;

const
//自军定义消息MSG_COPY:传送文件拷贝的进度信息;
//wParam: 后台线程的线程ID;
//lParam: 已拷贝的字节数;
MSG_COPY_COUNT = WM_USER + 100;
MSG_COPY_SUCESS = WM_USER + 101;
MSG_COPY_FAILED = WM_USER + 102;

type
//将指定文件名的源文件拷贝到指定文件名的目标文件的后台线程;
TCopyThread = class(TThread)
private
FSource: string;
//源文件名;
FTarget: string;
//目的文件名;
FMainHandle: THandle;
//调用本线程的主线程句柄;
// FFileSize: Integer;
//源文件大小;
FCopyCount: Integer;
//已拷贝的字节数;
FBufferSize: Integer;
//拷贝用缓冲区大小;
FDelayTime: Integer;
//线程休息等待时间;
procedure CopyStream(Src, Dest: TStream);
procedure SetBufferSize(const Value: Integer);
procedure SetDelayTime(const Value: Integer);
protected
procedure Execute;
override;
public
//如不需要后台线程反馈消息,调用时只用前两个参数即可;
constructor Create(ASrcFile, ADestFile: string;
AHandle: THandle = 0);
//BufferSize属性:设置复制时的缓冲区大小;
property BufferSize: Integer read FBufferSize write SetBufferSize;
property DelayTime: Integer read FDelayTime write SetDelayTime;
// property CopyCount: Integer read FCopyCount;
// property FileSize: Integer read FFileSize;
property Terminated;
end;


//判断文件是否存在并返回其大小;
function GetFileSize(AFile: string): Integer;

implementation

function GetFileSize(AFile: string): Integer;
begin

Result := 0;
if not FileExists(AFile) then
Exit;
with TFileStream.Create(AFile, fmOpenRead)do

try
Result := Size;
finally
Free;
end;

end;


{ TCopyThread }

constructor TCopyThread.Create(ASrcFile, ADestFile: string;
AHandle: THandle);
begin

inherited Create(True);
FSource := ASrcFile;
FTarget := ADestFile;
FMainHandle := AHandle;
Priority := tpIdle;
FBufferSize := $F000;
FreeOnTerminate := True;
end;


procedure TCopyThread.Execute;
var
Src, Dest: TFileStream;
begin

// if not FileExists(FSource) then
Exit;
Src := TFileStream.Create(FSource, fmOpenRead);
try
// FFileSize := Src.Size;
if FileExists(FTarget) then
DeleteFile(FTarget);
Dest := TFileStream.Create(FTarget, fmCreate);
try
CopyStream(Src, Dest);
finally
Dest.Free;
end;

finally
Src.Free;
end;

end;


procedure TCopyThread.CopyStream(Src, Dest: TStream);
var
Count, BufSize, N: Integer;
Buffer: Pointer;
//PChar;
begin

Count := Src.Size;
Src.Position := 0;
Dest.Position := 0;
if Count > FBufferSize then
BufSize := FBufferSize else
BufSize := Count;
GetMem(Buffer, BufSize);
try
while not Terminated and (Count <> 0)do

begin

if Count > BufSize then
N := BufSize else
N := Count;
Src.ReadBuffer(Buffer^, N);
Dest.WriteBuffer(Buffer^, N);
Dec(Count, N);
Inc(FCopyCount, N);

if FMainHandle <> 0 then
//反馈进度;
PostMessage(FMainHandle, MSG_COPY_COUNT, ThreadID, FCopyCount);
//让线程等待(由FDelayTime)指定的时间片;
if FDelayTime > 0 then
Sleep(FDelayTime);
end;

finally
FreeMem(Buffer, BufSize);
if FMainHandle <> 0 then
//反馈复制是否成功;
begin

if FCopyCount = Src.Size then

PostMessage(FMainHandle, MSG_COPY_SUCESS, ThreadID, FCopyCount)
else

PostMessage(FMainHandle, MSG_COPY_FAILED, ThreadID, FCopyCount);
end;

end;

end;


procedure TCopyThread.SetBufferSize(const Value: Integer);
begin

if (Value > 0) and (FBufferSize <> Value) then

FBufferSize := Value;
end;


procedure TCopyThread.SetDelayTime(const Value: Integer);
begin

if (Value > 0) and (FDelayTime <> Value) then

FDelayTime := Value;
end;


end.


 
以上的代码是拷贝多个文件,速度才会加快。
我要的是单个文件。因为是从光驱里读,而且影音文件都是较大的,所以想办法提高。

各位有什么看法啊?
 
软件估计是没什么办法了,这个主要是受你的硬件限制。
 
TO: shbjkl
读,写放在两个线程里面同步执行。可不可提高速度啊。
 
从光驱中读取的话,最好用单线程,从头到尾读,这样最快.可以做个测试,如果同时从光驱中读取多个文件,肯定比一个一个读取要慢得多,因为光驱浪费了好多时间在定位数据的寻道上了
 
楼上说的有道理。
我是从光碟读,然后写到硬盘上。
我的多线程的想法是:
读用一个线程,读是在光驱进行的,写用一个线程,写是在硬盘上进行的。
这样,硬盘和光驱都可以双工进行了。
这样读的时候也可以写,比起顺序读写是不是要快一些啊。
 
可是这样你还要同步读和写的两个线程,因为光驱比硬盘慢得多,如果同步不好还不如都写在一个线程中呢
 
我是这样想的。
先开二个缓冲区。
先执行读的线程,把要读的数据读到一个缓冲区去,然后执行写的线程。
读的线程继续读到第二个缓冲区去(这样可以避免写数据时停下来),直到缓冲区满了,写的线程实时监测缓冲区是否有数据
如果有,就写到硬盘去。主要是同步问题。
如果这样做复制文件能快一点,代码多写一些也没什么事。
 
做过类似的实验 读写分两个线程做有时候会加快有时候会更慢。
如果是IDE系统,本盘拷贝,这么做会更慢。因为会导致读写的无序交错,增加了寻道的开销,因为IDE系统对重叠IO请求的响应是很原始的。IDE的系统跨物理盘复制,如果是接在两个不同IDE通道是的话,可以提高很大速度,最终速度取决于最慢的那个盘,但是如果接在同一个IDE通道上的两个物理盘的话,速度则和普通的复制基本相同,因为任意时刻只能有一个设备在工作,而另一个在等待。
如果是SCSI系统,由于SCSI的智能化,可以对IO请求优化合并处理,这么做还是有一定好处,不过一定要控制住速度,每秒20MB/S以上的时候就很容易使系统的缓冲机制来不及处理,可用内存迅速减少到4M的基本值,而速度猛降。如果能避开系统的Cache就不会出现这个问题,可惜我不知道怎么做。
 
后退
顶部