Kopiowanie katalogu z progressem lub gauge kopia bazy danych

0

Witam wielmożnych guru w temacie,
w poniższym kodzie mam kopiowanie plików z jednego katalogu do drugiego. Niestety nie pokazuje ono przebiegu kopiowania. Mam pytanko jak do tego zrobić żeby pokazywało przebieg kopiowania progressbar lub guage oraz dawało wybór miejsca gdzie mają być umieszczone dane. dobrą funkcja było by odtworzenie też danych z katalogu kopia do katalogu dane.
W taki sposób powstanie cos w rodzaju tworzenia kopii danych.

Z góry dziękuję za zainteresowanie.
wiem że przykład jest troszkę długi ale prosze o pomoc, bo stoję z tym i nie moge ruszyć. Aha pisze w Delphi 5.

procedure TForm2.Button5Click(Sender: TObject);

var FOS:TSHFileOpStructA;
begin
with FOS do
begin
Wnd:=Handle;
wFunc:=FO_COPY;
pFrom:='c:\program\Dane*.*';
pTo:='c:\program\kopia';
fFlags:=FOF_ALLOWUNDO or FOF_NOCONFIRMMKDIR;
lpszProgressTitle:='Kopiowanie...';
fAnyOperationsAborted:=False;
end;
if SHFileOperation(FOS)<>0 then
ShowMessage('Wystąpił błąd podczas kopiowania')
else
if FOS.fAnyOperationsAborted then
ShowMessage('Kopiowanie zostało przerwane');
end;

Z góry dziękuję za zainteresowanie.
Serdecznie pozdrawiam
waldi

0

Czesc, mozesz zrealizowac progress bar na dwa sposoby(ktore w tym momencie mi przyszly do glowy) w zaleznosci od tego jak dokladny progress bar to ma byc.

Sposob 1 (dokladnosc do pliku):

Na poczatku musisz zliczyc ilosc plikow w katalogu zrodlowym, oraz pobrac sobie wszystkie sciezki do tych plikow. Oczywiscie ilosc plikow to Twoj TProgressBar.Max. Nastepnie dla kazdego pliku, ktorego masz sciezke, w petli wypelniasz sobie ta strukturke, ktora nam przedstawiles i wywolujesz ta funkcje WinAPI. Zmieniasz tylko pFrom na pojedyncze sciezki plikow. W petli zmieniasz TProgressBar.Position oraz wywolujesz Application.ProcessMessages. No i masz progress bara z dokladnoscia do pliku.

Sposob 2 (dokladnosc do bajtu):

Tak jak wczesniej, pobierasz sciezki do wszystkich plikow i zliczasz wielkosc kazdego pliku. Sumaryczna wielkosc wszystkich plikow = TProgressBar.Max. Reszte wykonujesz tak samo z tym ze inkrementujesz TProgressBar.Position o wielkosc ostatnio skopiowanego pliku. Proste ? ;)

Jakby co daj znac.

0

Witam,
Mam 4 pliki w tym katalogu Dane:
nazwiska.dbf, nazwiska.mdx, nazwiska.dbt i numer.dbf
Nie jestem dobry w te klocki i proszę o pomoc może coś w rodzaju gotowca do w/w przykładu.

Serdecznie pozdrawiam i proszę o wyrozumiałość
waldi

0

Witaj.

Formatowanie kodu nie zaszkodzi ;)

Wrzuc wrapper na ta funkcje Api(i na strukture, ktora jej podajesz) z ktorej korzystasz to cos poradzimy ;)

Naprawde, nie chce mi sie tego robic samemu. Jak chcesz gotowca, moglbys sie troche bardziej postarac ;)

0

Witam serdecznie,
mam pytanko ?

Wodzu napisał(a)

Witaj.

Formatowanie kodu nie zaszkodzi ;)

Wrzuc wrapper na ta funkcje Api(i na strukture, ktora jej podajesz) z ktorej korzystasz to cos poradzimy ;)

Naprawde, nie chce mi sie tego robic samemu. Jak chcesz gotowca, moglbys sie troche bardziej postarac ;)

a jak bardzo Ci nie chce się tego gotowca napisać ?
Prosze ...
Serdecznie pozdrawiam i dziękuję za zainteresowanie.
waldi

0

Moze zle sie wyrazilem ;)

Poprosze o przyklad kompilowalny i dzialajacy Twojego obecnego kopiowania...

0

Witam,
tu jest cały pas który tworzy tą całą procedurę kopiowania danych z jednego katalogu do katalogu i z powrotem.
Jest to jedna część z programu. Reszta programu to wprowadzanie danych i ich przeglądanie. Dlatego mam tu Form3

unit Unit3;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ShellApi,
StdCtrls, Gauges, ComCtrls;

type
TForm3 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Gauge1: TGauge;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure FormCreate(Sender: TObject);

private
{ Private declarations }
public
{ Public declarations }
end;

var
Form3: TForm3;

implementation

{$R *.DFM}

procedure TForm3.Button1Click(Sender: TObject); //tworzenie danych
var FOS:TSHFileOpStructA;
begin
with FOS do
begin
Wnd:=Handle;
wFunc:=FO_COPY;
pFrom:='c:\aprogram\Dane*.*';
pTo:='c:\aprogram\kopia';
fFlags:=FOF_ALLOWUNDO or FOF_NOCONFIRMMKDIR;
lpszProgressTitle:='Kopiowanie danych...';
fAnyOperationsAborted:=False;
end;
if SHFileOperation(FOS)<>0 then
ShowMessage('Wystąpił błąd podczas kopiowania')
else
if FOS.fAnyOperationsAborted then
ShowMessage('Kopiowanie zostało przerwane');

Application.MessageBox('Kopiowanie zakończono',
'Informacja', MB_ApplModal+MB_ICONINFORMATION or MB_OK);
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
Sleep(5000); // 5 sek 5000
Application.ProcessMessages; // nie blokuje działania programu
Gauge1.Progress:=100;
end;

procedure TForm3.Button2Click(Sender: TObject); //odtwarzanie danych
var FOS:TSHFileOpStructA;
begin
with FOS do
begin
Wnd:=Handle;
wFunc:=FO_COPY;
pFrom:='c:\aprogram\kopia*.*';
pTo:='c:\aprogram\Dane';
fFlags:=FOF_ALLOWUNDO or FOF_NOCONFIRMMKDIR;
lpszProgressTitle:='Kopiowanie danych...';
fAnyOperationsAborted:=False;
end;
if SHFileOperation(FOS)<>0 then
ShowMessage('Wystąpił błąd podczas kopiowania')
else
if FOS.fAnyOperationsAborted then
ShowMessage('Kopiowanie zostało przerwane');
Application.MessageBox('Zakończono odtwarzanie danych',
'Informacja', MB_ApplModal+MB_ICONINFORMATION or MB_OK);
end;

procedure TForm3.Button3Click(Sender: TObject);

var
numBtn: Integer;
begin
numBtn:= Application.MessageBox('na pewno Kończysz ?',
'Zakończenie pracy w formularzu',
MB_ICONQUESTION or MB_YESNO);
if (numBtn = IDYES) then
begin
ShowMessage('Hey to wychodzimy z tworznia kopii danych');
close
end;

end;
end.

Serdecznie pozdrawiam
Waldi

0

Czesc.

Juz zaczalem Ci pisac tego progress bara jednak stwierdzilem, ze poczytam jeszcze troche o tym:

TSHFileOpStructA

okazuje sie, ze wystarczy dodac do tej strukturki flage FOF_SIMPLEPROGRESS i bedziesz mial windowsowego progress bara. Czy tak moze byc?

Pozdrawiam.

0

Witam Wielmożnych Guru,
dopisałem do każdej procedury kopiowania tutaj:
fFlags:=FOF_ALLOWUNDO or FOF_NOCONFIRMMKDIR;
ten Twój FOF_SIMPLEPROGRESS
teraz mam taki kod:
fFlags:=FOF_ALLOWUNDO or FOF_NOCONFIRMMKDIR or FOF_SIMPLEPROGRESS;
musiałem dopisać OR ponieważ wyrzucał mi błędy:

[Error] Unit3.pas(42): Missing operator or semicolon.
[Error] Unit3.pas(42): Statement expected, but expression of type 'Integer' found.
[Error] Unit3.pas(66): Missing operator or semicolon
[Error] Unit3.pas(66): Statement expected, but expression of type 'Integer' found
[Fatal Error] Adreska.dpr(9): Could not compile used unit 'Unit3.pas'
Nie wiem czy dobrze zrobiłem dopisując te or
Efekt jest taki że pokazuje mi kopiowanie tak jak jest w windows "żółte koperty". Na szybkim komputerze nie ma tego widocznego efektu. Gdyby coś takiego zrobić żeby użytkownik widział postęp np. w procentach Tgauge lub jakoś inaczej. Chodzi o to żeby był widoczny postęp kopiownia.
Serdecznie pozdrawiam i dziękuję za wyrozumiałość
Waldi

0

Czesc.

Twoj upor w dazeniu do celu zostal nagrodzony ;P Zrobie Ci gotowca jednakze chcialbym Ci takze pokazac jak winien przebiegac Twoj proces myslowy, moze to Ci ulatwi pisanie kodu w przyszlosci...

Wodzu napisał(a)

Sposob 2 (dokladnosc do bajtu):

Tak jak wczesniej, pobierasz sciezki do wszystkich plikow i zliczasz wielkosc kazdego pliku. Sumaryczna wielkosc wszystkich plikow = TProgressBar.Max. Reszte wykonujesz tak samo z tym ze inkrementujesz TProgressBar.Position o wielkosc ostatnio skopiowanego pliku. Proste ? ;)

Tutaj masz wszystko co potrzeba aby sobie zaimplementowac ten postep.

Wodzu napisał(a)

...zliczasz wielkosc kazdego pliku

Musimy znalezc metode na znalezienie wielkosci danego pliku. Moze cos z "file" i "size" bedzie w helpie Delphi? No patrz! Jest:

FileSize - Returns the current size of a file; not used for text files.

W dodatku Delphi 7 prawie od razu daje nam przyklad na kopiowanie pliku. To chyba nasz szczesliwy dzien ;).

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 }
      repeat
        BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
        BlockWrite(ToF, Buf, NumRead, NumWritten);
      until (NumRead = 0) or (NumWritten <> NumRead);
      CloseFile(FromF);
      CloseFile(ToF);
    end;
  end;

Wystarczy do tego dodac dwie linie kodu aby miec postep kopiowania pliku. Ale pierwej przerobmy to na procedurke i ogarnijmy troche kod.

procedure CopyFileWithProgress(const AFrom, ATo: String; var AProgress: TProgressBar);
var
  FromF, ToF: file;
  NumRead, NumWritten, DataSize: Integer;
  Buf: array[1..2048] of Char;
begin
  DataSize := SizeOf(Buf);
  AssignFile(FromF, AFrom);
  Reset(FromF, 1);
  AssignFile(ToF, ATo);
  Rewrite(ToF, 1);
  repeat
    BlockRead(FromF, Buf, DataSize, NumRead);
    BlockWrite(ToF, Buf, NumRead, NumWritten);
    AProgress.Position := AProgress.Position + DataSize;
    Application.ProcessMessages;
  until (NumRead = 0) or (NumWritten <> NumRead);
  CloseFile(FromF);
  CloseFile(ToF);
end;

Jako parametr przekazujemy oprocz sciezek do plikow rowniez TProgressBar gdyz musimy zmieniac jego pozycje.

Mamy wiec kopiowanie jednego pliku z postepem operacji (gdy znamy wczesniej rozmiar tego pliku).

Teraz pora na skorzystanie z kolejnej wskazowki:

Wodzu napisał(a)

pobierasz sciezki do wszystkich plikow

Czesto walkowany temat na forum ale jak gotowiec to gotowiec ;) Pozwolilem sobie napisac funkcje przeszukujaca rekurencyjnie dany katalog i znajdujaca pliki do kopiowania. Wyglada ona tak:

procedure GatherFilesFromDirectory(const ADirectory: String;
  var AFileList: TStringList; var ATotalSize: Int64);
var
  SR: TSearchRec;
begin
  if FindFirst(ADirectory + '\*.*', faDirectory, sr) = 0 then
  begin
    repeat
      if ((SR.Attr and faDirectory) = SR.Attr) and (SR.Name <> '.') and (SR.Name <> '..') then
        GatherFilesFromDirectory(ADirectory + '\' + Sr.Name, AFileList, ATotalSize);
    until FindNext(SR) <> 0;
    FindClose(SR);
  end;

  if FindFirst(ADirectory + '\*.*', 0, SR) = 0 then
  begin
    repeat
      AFileList.Add(ADirectory + '\' + SR.Name);
      Inc(ATotalSize, SR.Size);
    until FindNext(SR) <> 0;
    FindClose(SR);
  end;
end;

ADirectory to folder startowy. AFileList to wskaznik na TStringList w ktorej trzymamy znalezione sciezki do plikow. Dodatkowo w ATotalSize mamy wielkosc w bajtach wszystkich znalezionych plikow, potrzebne do TProgressBar.Max.

No i w sumie gotowe. Mozna z tego skorzystac np tak:


procedure TfmMain.btCopyClick(Sender: TObject);
var
  FileList: TStringList;
  TotalSize: Int64;
  i: Integer;
begin
  TotalSize := 0;
  FileList := TStringList.Create;
  GatherFilesFromDirectory(edCopyFrom.Text, FileList, TotalSize);
  pbProgress.Position := 0;
  pbProgress.Max := TotalSize;
  for i := 0 to FileList.Count - 1 do
  begin
    lbFile.Caption := 'Plik ' + FileList[i];
    CopyFileWithProgress(FileList[i], edCopyTo.Text + ExtractFileName(FileList[i]), pbProgress);
  end;
  FileList.Free;
end;

Dodatkowo bedzie pokazywalo nazwe aktualnie kopiowanego pliku.

Pod tym linkiem znajdziesz program ze zrodlami:

http://www.speedyshare.com/527574196.html

Pozdrawiam

PS. Polecam ProgressBary z pakietu komponentow JEDI.

0

Witam,
Jestem pod wrażeniem. Efekt jest SUPER !!! zwłaszcza to kopiowanie z podaniem nazw plików.
Niestety ja pisze w 5 i coś mi nie chce to chodzić. Nie wiem czy wynika to z mojego błędu a może z mojej nie wiedzy. U mnie w programie jest tak:

  1. Program uruchamiam,
  2. Klikam na button kopia bazy
  3. pokazuje się okienko z 3 buttonami /wykonaj kopie/ , /odtwórz/, /wyjscie/;
  4. klikam na /Wykonaj kopie/ i kopiowane są pliki z katalogu dane do katalogu kopia

I gdyby tu można pokazać postęp kopiowania plików to by było EXTRA.

Odtwarzanie danych polega na wywołaniu tej samej procedury ;-)tyle tylko że są kopiowane pliki z katalogu kopia do katalogu Dane.

Tylko o to mi chodzi. Jaki ja bym był szczęśliwy gdybym to miał.
Serdecznie pozdrawiam
Waldi

0

Jakie masz bledy?

Sprawdz czy pliki ktore chcesz kopiowac sa tylko do odczytu, jesli tak to musisz zmienic globalna zmienna

FileMode

a nawet powinienes ja zmienic na tryb tylko do odczytu.

0

witam,
Twoja procedurę "podpiołem" do mojego Buttona, musiałem dopisac copy. Tak teraz wygląda procedura;
ściezka dostepu do danych;
c:\program4\Dane\moje_pliki
Tu sa przechowywane pliki ktore chce kopiwać, archiwizowac tak jak opisałem w poprzednim poscie
Błąd chyba jest bo nie podałem pełnej ściezki dostepu ?
Czy gdzieś jeszcze indziej ?
Dla pełniejszego sp[ojrzenia na problem poniżej zapisałem kod taki jaki mam w programie.

procedure TForm3.Button1copyClick(Sender: TObject); //tworzenie danych
var
FileList: TStringList;
TotalSize: Int64;
i: Integer;
begin
TotalSize :=0;
FileList :=TStringList.Create;
GatherFilesFromDirectory(edCopyFrom.Text, FileList, TotalSize);
  pbProgress.Position := 0;
  pbProgress.Max := TotalSize;
  for i := 0 to FileList.Count - 1 do
  begin
    lbFile.Caption := 'Plik ' + FileList[i];
    CopyFileWithProgress(FileList[i], edCopyTo.Text + ExtractFileName(FileList[i]), pbProgress);
  end;
  FileList.Free;
end;
   Application.MessageBox('Kopiowanie zakończono',
    'Informacja', MB_ApplModal+MB_ICONINFORMATION or MB_OK);

  end;

[Error] Unit3.pas(42): Undeclared identifier: 'GatherFilesFromDirectory'
[Error] Unit3.pas(42): Undeclared identifier: 'edCopyFrom'
[Error] Unit3.pas(42): Missing operator or semicolon
[Error] Unit3.pas(45): ';' expected but 'FOR' found
[Error] Unit3.pas(47): Undeclared identifier: 'lbFile'
[Error] Unit3.pas(47): Undeclared identifier: 'FileList'
[Error] Unit3.pas(48): Undeclared identifier: 'CopyFileWithProgress'
[Error] Unit3.pas(48): Undeclared identifier: 'edCopyTo'
[Error] Unit3.pas(48): '(' expected but '+' found
[Error] Unit3.pas(48): Incompatible types: 'String' and 'Text'
[Error] Unit3.pas(49): '.' expected but ';' found
[Warning] Unit3.pas(51): Text after final 'END.' - ignored by compiler
[Error] Unit3.pas(16): Unsatisfied forward or external declaration: 'TForm3.Button2Click'
[Error] Unit3.pas(17): Unsatisfied forward or external declaration: 'TForm3.Button3Click'
[Fatal Error] Adreska.dpr(9): Could not compile used unit 'Unit3.pas'

Serdecznie pozdrawiam i licze na wyrozumiałość
Waldi

0

Oj bracie teraz to... zamurowales mnie :)

Czy Ty wiesz co znacza te bledy ktore zwraca kompilator...? Hmmm.....

Podepnij do swojego programu unita uProcedures, ktorego zamiescilem wraz z kodem zrodlowym.
Dodaj go do listy uses tam gdzie masz TForm3.
W

GatherFilesFromDirectory(edCopyFrom.Text, FileList, TotalSize);

zamiast edCopyFrom.Text podaj sciezke skąd bierzesz pliki.
Analogicznie, pozmieniaj inne wartosci na odpowiednie wywalajac komponenty, ktore byly uzyte w przykladzie.

Spojrz uwaznie, w zrodla programu ktory Ci dalem. Nie mozesz przekopiowac calego kodu i liczyc ze bedzie dzialal..... [glowa] [glowa] [glowa]

0

Witam,
Ja już się w tym wszystkim pogubiłem <beczy>
Serdecznie pozdrawiam
Waldi

0

OK moi GURU,
wszystko wygląda ładnie, ale pliki większe niż 2 GB kopiują sie tylko do wspomnianej granicy i program zgłasza, że zakończył kopiowanie.

Robił już ktoś coś takiego, żeby kopiować plik np. 10GB?

Dodam jeszcze, że polecenie copyfile nie wchodzi w grę, ponieważ nie chce korzystać z shella windowsów. Co do ProgressBara, proponuję zastosować Gauge z palety Samples:

...
gauge1.MaxValue := filesize(file_in);
...
repeat
BlockRead(file_in, bufor, 1024, wynik);
BlockWrite(file_out, bufor, 1024, wynik);
gauge1.Progress := filepos(file_in);
Application.ProcessMessages; //żeby ładnie się odświeżała forma
until Eof(file_in);
...

pozdrawiam i dzięki za odpowiedź

itepe

0

Odgrzeje stary temat ale niektorzy ludzie zalamuja i pisza "jestem dobry w te klocki" ja programuje ponad 2 lata i uwazam ze wcale taki dobry nie jestem, co do duzych plikow podpowiedz:

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

tu należy szukać buga :)

0

ludzie dajcie ten temat do Newbie bo mi się płakać chce.

1 użytkowników online, w tym zalogowanych: 0, gości: 1