В данной статье показаны некоторые методы копирования файлов.
Существуют и готовые функции - CopyFile(), CopyFileEx(), но порой они
неприменимы. Например, при использовании функции CopyFile() с большими файлами
мы не имеем доступа к процессу копирования, т.е. программа на некоторое время
просто "зависает". Из методов, приведённых ниже, только первый позволяет
контроллировать процесс копирования - можно добавить прогресс-индикатор
выполнения или отображать объём скопированных данных.
1. Копирование методом Pascal
type
TCallBack=procedure (Position,Size: Longint); {Для индикации процесса копирования}
procedure FastFileCopy(Const InfileName, OutFileName: String; CallBack: TCallBack);
const BufSize = 3*4*4096; { 48Kbytes дает прекрасный результат }
type
PBuffer = ^TBuffer;
TBuffer = array [1..BufSize] of Byte;
var
Size : integer;
Buffer : PBuffer;
infile, outfile : File;
SizeDone,SizeFile: Longint;
begin
if (InFileName <> OutFileName) then
begin
buffer := Nil;
AssignFile(infile, InFileName);
System.Reset(infile, 1);
try
SizeFile := FileSize(infile);
AssignFile(outfile, OutFileName);
System.Rewrite(outfile, 1);
try
SizeDone := 0; New(Buffer);
repeat
BlockRead(infile, Buffer^, BufSize, Size);
Inc(SizeDone, Size);
CallBack(SizeDone, SizeFile);
BlockWrite(outfile,Buffer^, Size)
until Size < BufSize;
FileSetDate(TFileRec(outfile).Handle,
FileGetDate(TFileRec(infile).Handle));
finally
if Buffer <> Nil then Dispose(Buffer);
System.Close(outfile)
end;
finally
System.Close(infile);
end;
end
else
Raise EInOutError.Create('File cannot be copied into itself');
end;
2. Копирование методом потока.
procedure FileCopy(Const SourceFileName, TargetFileName: String);
var
S,T: TFileStream;
begin
S := TFileStream.Create(sourcefilename, fmOpenRead);
try
T := TFileStream.Create(targetfilename, fmOpenWrite or fmCreate);
try
T.CopyFrom(S, S.Size);
FileSetDate(T.Handle, FileGetDate(S.Handle));
finally
T.Free;
end;
finally
S.Free;
end;
end;
3. Копирование методом LZExpand
uses LZExpand;
procedure CopyFile(FromFileName, ToFileName : string);
var
FromFile, ToFile: File;
begin
AssignFile(FromFile, FromFileName);
AssignFile(ToFile, ToFileName);
Reset(FromFile);
try
Rewrite(ToFile);
try
if LZCopy(TFileRec(FromFile).Handle, TFileRec(ToFile).Handle) < 0 then
raise Exception.Create('Error using LZCopy')
finally
CloseFile(ToFile);
end;
finally
CloseFile(FromFile);
end;
end;
4. Копирование методами Windows
uses ShellApi;
function WindowsCopyFile(FromFile, ToDir : string) : boolean;
var F : TShFileOpStruct;
begin
F.Wnd := 0; F.wFunc := FO_COPY;
FromFile:=FromFile+#0; F.pFrom:=pchar(FromFile);
ToDir:=ToDir+#0; F.pTo:=pchar(ToDir);
F.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION;
Result:=ShFileOperation(F) = 0;
end;
// Пример копирования:
procedure TForm1.Button1Click(Sender: TObject);
begin
if not WindowsCopyFile('C:\UTIL\ARJ.EXE', GetCurrentDir) then
ShowMessage('Copy Failed');
end;
Мной были сделаны некоторые эксперименты с данными функциями.
Во всех случаях копировался один и тот же файл объёмом 122 Мб. Конечно, говорить
о правильности результатов можно с трудом, ведь жёсткий диск работает по-разному
- иногда быстрее, а иногда медленее. Но в любом случае, результаты есть:
Метод |
Опыт 1 (сек.) |
Опыт 2 (сек.) |
Средняя скорость |
1
|
3.355
|
3.515
|
3.435
|
2
|
4.467
|
4.286
|
4.377
|
3
|
3.545
|
3.395
|
3.470
|
4
|
3.696
|
5.478
|
4.587
|
Кажется, название функции FastFileCopy вполне оправдано.
Впрочем, судить о том, какая из функций действительно работает быстрее, нужно по
результатам экспериментов на большом числе компьютеров с разными конфигурациями.
Но цель данной статьи была не выявить самый быстрый способ, а просто показать об
этих способах. Использовать можно любой из методов, все они работоспособны.
|