Delphi.int.ru — Портал программистов

Вход Регистрация | Забыли пароль?

События

Сегодня:
Вопросы0    Ответы0    Мини-форумы0


Последние:
Вопрос10.11, 12:07 / #6676
Ответ02.08, 00:42 / #6619
Новости30 апреля 2012


Сейчас онлайн:
На сайте — 8
На IRC-канале — 2

Ссылки

Копирование файлов

Автор: Ерёмин Андрей
Использованы материалы: dmitry9.nm.ru

В данной статье показаны некоторые методы копирования файлов. Существуют и готовые функции - 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 вполне оправдано. Впрочем, судить о том, какая из функций действительно работает быстрее, нужно по результатам экспериментов на большом числе компьютеров с разными конфигурациями. Но цель данной статьи была не выявить самый быстрый способ, а просто показать об этих способах. Использовать можно любой из методов, все они работоспособны.

Автор: Ерёмин А.А.

Статья добавлена: 16 февраля 2006

Следующая статья: Работа со строковыми типами данных »

Рейтинг статьи: 5.00 Голосов: 6 Ваша оценка:

Зарегистрируйтесь/авторизируйтесь,
чтобы оценивать статьи.


Статьи, похожие по тематике

 

Для вставки ссылки на данную статью на другом сайте используйте следующий HTML-код:

Ссылка для форумов (BBCode):

Быстрая вставка ссылки на статью в сообщениях на сайте:
{{a:19}} (буква a — латинская) — только адрес статьи (URL);
{{статья:19}} — полноценная HTML-ссылка на статью (текст ссылки — название статьи).

Поделитесь ссылкой в социальных сетях:


Комментарии читателей к данной статье

Ерёмин А.А.
Репутация: +40

Ерёмин А.А. (8 января 2012, 23:26):

Цитата (нескажу):

Подскажите плиз, как делать индикацию в 1 случае?

Взять размер файла с помощью FileSize(), ну а дальше понятно, надеюсь.
нескажу
Репутация: нет

нескажу (8 января 2012, 13:27):

Подскажите плиз, как делать индикацию в 1 случае?
Ерёмин А.А.
Репутация: +40

Ерёмин А.А. (26 апреля 2009, 23:21):

А в чём проблема? Не умеем циклы писать? :-)
demyan
Репутация: нет

demyan (26 апреля 2009, 17:43):

Отлично.
Еще бы про то как 10 файлов скопировать сразу а не один как на примере.

Оставлять комментарии к статьям могут только зарегистрированные пользователи.