2009-10-19 14 views
6

W mojej aplikacji trzeba skopiować ponad 1000 małych plikówKopiowanie wielu plików w Delphi

Oto kod używam, ale jest to bardzo powolny Czy istnieje lepszy sposób to zrobić?

procedure Tdatafeeds.RestotreTodaysFiles; 
var 
    SearchRec: TSearchRec; 
    FromFn, ToFn: string; 
Begin 
    if DirectoryExists(BackupPath1) then 
    begin 
     try 
     if FindFirst(BackupPath1 + '\*.*', (faAnyFile AND NOT(faDirectory)), SearchRec) = 0 then 
     begin 
      repeat 
      FromFn := BackupPath1 + '\' + SearchRec.name; 
      ToFn := DatafeedsPath1 + '\' + SearchRec.name; 
      CopyFile(Pchar(FromFn), Pchar(ToFn), false); 
      until FindNext(SearchRec) <> 0; 
     end; 
     finally 
     FindClose(SearchRec); 
     end; 
    end; 
End; 
+1

Kopiowanie wielu małych plików może spowodować problemy z wejściem/wyjściem, szczególnie w przypadku wolniejszych dysków. Głowice dysków muszą dużo ruszać, aby szukać plików i znaleźć wolne miejsce do ich kopiowania. Jeśli skopiujesz te pliki z wiersza poleceń, czy system jest znacznie szybszy? –

Odpowiedz

10

Zdecydowanie iść z SHFileOperation() jak zasugerowano powyżej, CopyFile jest zbyt powolne, że wiele plików . Wygląda na to, że zasadniczo przywracasz cały folder, więc funkcja wyszukiwania może być niepotrzebna, a rzeczy spowalniające. Coś takiego może być pomocne:

uses ShellApi; 

function CopyDir(const fromDir, toDir: string): Boolean; 
var 
    fos: TSHFileOpStruct; 
begin 
    ZeroMemory(@fos, SizeOf(fos)); 
    with fos do 
    begin 
    wFunc := FO_COPY; 
    fFlags := FOF_FILESONLY; 
    pFrom := PChar(fromDir + #0); 
    pTo := PChar(toDir) 
    end; 
    Result := (0 = ShFileOperation(fos)); 
end; 

Funkcja ta podniesie się monit, aby zastąpić istniejące pliki chociaż (a może to mogą być manipulowane, aby pominąć te), ale użytkownik może wybrać „All”, więc jest to jednym kliknięciem procedura, znacznie szybsza, ma pasek postępu i może być anulowana w razie potrzeby.

+1

Zobacz flagi ** FOF_NOCONFIRMATION ** i ** FOF_NOCONFIRMMKDIR **, aby uniknąć jakichkolwiek monitów. Więcej informacji: http://msdn.microsoft.com/en-us/library/bb759795%28VS.85%29.aspx – stukelly

+5

Co sprawia, że ​​funkcja SHFileOperation() jest szybsza niż CopyFile? –

0

Być może eksperymentować z czytania kilka plików do pamięci, a następnie zapisuje je na dysku wszystko na raz (jak XCOPY). To może być ładniejsze w systemie plików.

7

Można użyć wywołania API SHFileOperation() i użyć wieloznacznika w nazwie pliku struktury. W ten sposób jedno połączenie zostanie użyte do skopiowania wszystkich plików za jednym razem. Istnieje nawet możliwość wyświetlenia postępu (poprzez funkcję zwrotną) i umożliwienia użytkownikowi anulowania operacji.

+0

CopyFileEx() pozwoli również na oddzwonienie i zastanawiałbym się, czy SHFileOperation nie zakończyłby się wywołaniem CopyFileEx(). –

+1

To prawda, ale AFAICS z dokumentacji MSDN 'CopyFileEx()' nie zezwala na symbole wieloznaczne dla źródła. Zatem użycie 'SHFileOperation()' (lub interfejsu 'IFileOperation' w systemie Vista i poza nim) również zastąpiłoby pętlę find file. – mghie

+0

Dzięki - SHFileOperation() działa dobrze kopia zajmuje teraz kilka sekund - zanim zajęło to minuty :) –

2

nie mogę przetestować swój kod w tej chwili, ale sprawdzić to poprawione wersja

// (!) faAnyFile-faDirectory <--- this is wrong 
    // we don't subtract flag values because the value will be meaningless 
    if FindFirst(BackupPath1 + '\*.*', faAnyFile, SearchRec) = 0 then 
    begin 
     repeat 
     if not (SearchRec.Attr and faDirectory) 
      And SearchRec.Name <> "." 
      And SearchRec.Name <> ".." Then 
     Begin 
      FromFn := BackupPath1 + '\' + SearchRec.name; 
      ToFn := DatafeedsPath1 + '\' + SearchRec.name; 
      CopyFile(Pchar(FromFn), Pchar(ToFn), false); 
     End; 
     until FindNext(SearchRec) <> 0; 
     FindClose(SearchRec); 
    end; 
Powiązane problemy