Lazarus и Free Pascal - Как рекурсивно скопировать исходный каталог файлов в другой каталог?

Мне нужно добавить некоторые функции в мою программу с графическим интерфейсом Lazarus и Free Pascal - мне нужно, чтобы она также копировала файлы из выбранного пользователем каталога в другой каталог. У меня есть событие onclick кнопки TSelectDirectoryDialog «Выбрать источник» для исходного каталога и событие onclick кнопки TSelectDirectoryDialog «Выбрать место назначения» для целевого каталога. У меня есть третья кнопка для копирования из источника в место назначения.

До сих пор я нашел CopyFile, который копирует файлы и исходные атрибуты даты, но не воссоздает структуру подкаталогов каких-либо подкаталогов выбранного пользователем исходного каталога. По сути, я пытаюсь реплицировать исходный каталог в новом каталоге в другом месте.

Я зашел так далеко:

Public Vars :
DestDir, SourceDir : string
...
FS := TFileSearcher.Create;
FS.OnFileFound := @CopyTheFile;  // CopyTheFile is my own procedure 
FS.Search(SourceDir, '*', True);   
...

procedure TForm1.CopyTheFile(FileIterator: TFileIterator);
var
  DestinationName: String;
begin
  DestinationName := IncludeTrailingPathDelimiter(DestDir) + ExtractFileName(FileIterator.FileName);
  if not FileUtil.CopyFile(FileIterator.FileName, DestinationName, true) then
    ShowMessage(FileIterator.FileName + ' failed to copy');
end;        

Может ли кто-нибудь помочь мне с кодом при копировании подкаталогов и их файлов? Я также задал вопрос на форуме Lazarus здесь: Тема Lazarus

Большое спасибо

Тед


person Gizmo_the_Great    schedule 14.02.2012    source источник
comment
В Python, например, это так же просто: .python.org/library/shutil.html" rel="nofollow noreferrer">docs.python.org/library/shutil.html)   -  person Gizmo_the_Great    schedule 21.02.2012
comment
Собираетесь ли вы использовать только платформу Windows или вам нужна независимая платформа? Я спрашиваю, потому что Windows Shell может сделать это с одной функцией, я думаю (то же самое, скорее всего, будет, например, в Linux).   -  person TLama    schedule 22.02.2012
comment
Привет TLama. Я только что заметил твой комментарий. Извините за задержку. Я только что опубликовал свой собственный ответ ниже, поэтому, пожалуйста, не тратьте на него свое время. Но чтобы ответить на ваш вопрос, он должен быть независимым от ОС, поскольку он кроссплатформенный. Мне еще предстоит более тщательно проверить свой ответ, но он должен хорошо работать как в Linux (проверено), так и в Windows (не проверено). Тед   -  person Gizmo_the_Great    schedule 22.02.2012


Ответы (1)


Я ОЧЕНЬ РАД И ГОРД, что впервые дал ответ на свой вопрос! Я вернул все к основам и перестал читать более сложные примеры других людей (потому что они просто сбили меня с толку). Я придерживался основных процедур, перечисленных в ссылка на Lazarus FileUtils. и придумал это, что работает. Мне нужно встроить проверку ошибок и прочее, но теперь у меня есть код, который берет исходный каталог, перестраивает его в целевой каталог, а затем копирует файлы из исходного каталога в целевой, используя только код Free Pascal и не Синтаксис ОС. Вставлено ниже для пользы других. Пожалуйста, добавляйте любые конструктивные комментарии, чтобы сделать его лучше, быстрее, эффективнее. Спасибо.

procedure TForm1.Button3Click(Sender: TObject);
begin
  ProcessDir(SourceDir);
end;

procedure TForm1.ProcessDir(const SourceDirName: string);

var
  NoOfFilesFoundInSourceDir, i, NoOfFilesCopiedOK : integer;
  FilesFoundToCopy : TStringList;
  SourceDirectoryAndFileName, SubDirStructure, FinalisedDestDir, FinalisedFileName : string;

begin
  Memo1.Lines.Clear;
  SubDirStructure := '';
  FinalisedDestDir := '';
  NoOfFilesFoundInSourceDir := 0;
  NoOfFilesCopiedOK := 0;

  // Ensures the selected source directory is set as the directory to be searched
  // and then fina all the files and directories within, storing as a StringList.

  SetCurrentDir(SourceDirName);
  FilesFoundToCopy := FindAllFiles(SourceDirName, '*', True);
  NoOfFilesFoundInSourceDir := FilesFoundToCopy.Count;

  try
    for i := 0 to FilesFoundToCopy.Count -1 do
      begin
        Memo1.Lines.Add('File Index : '+IntToStr(i)+' File Name: '+FilesFoundToCopy.Strings[i]);
        SourceDirectoryAndFileName := ChompPathDelim(CleanAndExpandDirectory(FilesFoundToCopy.Strings[i]));

    // Determine the source sub-dir structure, from selected dir downwards

    SubDirStructure := IncludeTrailingPathDelimiter(ExtractFileDir(SourceDirectoryAndFileName));

    // Now concatenate the original sub directory to the destination directory and form the total path, inc filename
    // Note : Only directories containing files will be recreated in destination. Empty dirs are skipped.
    // Zero byte files are copied, though, even if the directory contains just one zero byte file.

    FinalisedDestDir := DestDir+SubDirStructure;
    FinalisedFileName := ExtractFileName(FilesFoundToCopy.Strings[i]);

    // Now create the destination directory structure, if it is not yet created. If it exists, just copy the file.

    if not DirPathExists(FinalisedDestDir) then
      begin
        if not ForceDirectories(FinalisedDestDir) then
          begin
            ShowMessage(FinalisedDestDir+' cannot be created.');
          end;
      end;

    // Now copy the files to the destination dir

    if not FileUtil.CopyFile(SourceDirectoryAndFileName, FinalisedDestDir+FinalisedFileName, true) then
      begin
        ShowMessage('Failed to copy file : ' + SourceDirectoryAndFileName)
      end
    else
    NoOfFilesCopiedOK := NoOfFilesCopiedOK + 1;
  end;
  finally
    FilesFoundToCopy.free;
  end;
  ShowMessage('Total files copied OK : ' + IntToStr(NoOfFilesCopiedOK));
end;       
person Gizmo_the_Great    schedule 22.02.2012