Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Daten Kopieren mit Thread? (https://www.delphipraxis.net/156301-daten-kopieren-mit-thread.html)

WizoHulk 27. Nov 2010 06:25

Daten Kopieren mit Thread?
 
Hallo DP's

ich hab ein kleines Problem, und zwar möchte ich Dateien kopieren. was soweit auch ganz gut mit den Source klappt.
Delphi-Quellcode:
class function TMyDaten.CopyDirectory(AFromFolder, AToFolder: string): boolean;
var
  fos: TSHFileOpStruct;
begin
  ZeroMemory(@fos, SizeOf(fos));
  fos.wFunc := FO_COPY;
  fos.fFlags := FOF_SIMPLEPROGRESS OR FOF_NOCONFIRMATION;
  fos.pFrom := PChar(AFromFolder + #0);
  fos.pTo := PChar(AToFolder);
  Result := (0 = ShFileOperation(fos));
end;
Nun habe ich aber festgestellt, das wenn größere Datenmengen Transportiert, das er nicht weiterkomperliert bis die Datei oder Verzeichnis erfolgreich beendet wurde.
Meine Idee war die Funktion in einem Thread zu haun und dann nur die Parameter zu übergeben.
Delphi-Quellcode:
LThread := MyThread.Create(true);
      LThread.GPfadFrom := LPfadFrom;
      LThread.GFadTo := LPfadTo;
      LThread.Suspended := False;  //thread wird gestartet!!
      Application.ProcessMessages;
aber da ist wieder das Problem das er erst nach meiner For - Schleife mit den kopieren anfängt.

hat jemand eine Idee wie man das am einfachsten lösen kann?
Mein ziel ist, das er währen meiner Fußgesteuerten schleife...
Delphi-Quellcode:
repeat
        FileCountTo := TMyDaten.CountFiles(LPfadTo); //ermittelt OrdnerZahl
        Progressbar1.Position := FileCountTo;
        Application.ProcessMessages;
      until FileCountTo = FFileCountFrom;
...Die Dateien kopiert..

danke schonmal im Vorraus.

Bummi 27. Nov 2010 07:55

AW: Daten Kopieren mit Thread?
 
Übergib dem Thread doch einen Zeiger auf eine Array mit allen zu kopierenden Ordnern (vorher sammeln) und lass Dich im OnTerminate informieren wenn er fertig ist.

s.h.a.r.k 27. Nov 2010 09:01

AW: Daten Kopieren mit Thread?
 
Hallo erst mal :)

Kurz mal ein Hinweis zu
Delphi-Quellcode:
ShFileOperation()
-- wenn du also Threads nutzen willst, unbedingt absolute Pfade verwenden:
Zitat:

Zitat von http://msdn.microsoft.com/en-us/library/bb762164%28VS.85%29.aspx
You should use fully-qualified path names with this function. Using it with relative path names is not thread safe.

Zitat:

Zitat von WizoHulk (Beitrag 1064380)
Nun habe ich aber festgestellt, das wenn größere Datenmengen Transportiert, das er nicht weiterkomperliert bis die Datei oder Verzeichnis erfolgreich beendet wurde.

Ich glaube, du verwechselst hier was oder solltest dir darüber klar werden, was unter compilieren zu verstehen ist. Du meinst wohl, dass das Programm nicht mehr reagiert, wenn du große Dateien kopierst?!

Delphi-Quellcode:
LThread := MyThread.Create(true);
      LThread.GPfadFrom := LPfadFrom;
      LThread.GFadTo := LPfadTo;
      LThread.Suspended := False;  //thread wird gestartet!!
      Application.ProcessMessages;
Irgendwie seltsamer Code ;) Das mit den Properties kannst du so handhaben, das geht schon in Ordnung. Für das Starten des Threads gibt es doch die Methode
Delphi-Quellcode:
Start()
, d.h. du solltest es so machen:

Delphi-Quellcode:
LThread := MyThread.Create(true);
LThread.GPfadFrom := LPfadFrom;
LThread.GFadTo := LPfadTo;
LThread.Start(); // ab hier läuft dann der Kopierthread los
// Application.ProcessMessages; <<< das hier braucht es nicht

WizoHulk 27. Nov 2010 15:51

AW: Daten Kopieren mit Thread?
 
das mit dem Thread haut hin.
jetzt will ich aber prüfen ob er denn Fertig ist mit der übertragung, damit er mit der neuen Operation anfangen kann daten zu kopieren.
hatte das mit einer schleife gemacht. das klappt aber auch net so ganz.

am besten ich zeug ma den ganzen source um überhaupt da mal durchzublicken...

Delphi-Quellcode:
unit Unit1;

procedure TForm1.ConnectToDB;
var
  LDBPfad: String ;
begin
  LDBPfad := TMyDaten.GetMyPath;
    FDBPfad := LDBPfad + 'MyDatenbank.accdb';                                        //     D:\FastBackup\MyDatenbank.accdb
    try
  //    adoConBackupper.Connected := true;
      adoConBackupper.ConnectionString := TMyaccessDB.ConnectionToACCDB(FDBPfad);
     //adoConBackupper.ConnectionString := 'Provider=Microsoft.ACE.OLEDB.12.0;Data Source=' + FDBPfad +';Persist Security Info=False';
      lProcessStatus.Caption := 'Verbindung zur Datenbank wird aufgebaut...';
    except
      lProcessStatus.Caption := 'Fehler beim Verbinden...';
    end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin

    GlassFrame.Enabled:= true;
    Height := 0;
    left := Screen.Width - Width;
    top := Screen.Height;
    Timer2.enabled := true;
end;

procedure TForm1.StartingProcess;
var
    LThread: MyThread;
    lFileCountFrom, LRecordCount: Integer;
    LSql,LDateNow,LBackupString: String;
    LStatus, LPfadFrom, LPfadTo : String;
    LAddDate, LReplaceDate,LReplaceFolder,LDateiCode, LAddBackupString: Boolean;
    LReccord: Integer;
    I,x: Integer;
begin
  ConnectToDB;

  QuerryBackupper.Close;
  QuerryBackupper.SQL.Text := 'SELECT COUNT (*) FROM MyBackup WHERE deltag = ''t'' and Status = ''aktiv''';
  QuerryBackupper.open;
  LRecordCount := QuerryBackupper.Fields[0].asInteger;
  QuerryBackupper.Close;


  TMyaccessDB.SelectQuerry(QuerryBackupper,
                            'id, backupname,Pfad, Pfad_export,add_date,replace_folder,datei_code,add_backup_string',
                            'MyBackup','deltag = ''t'' and Status = ''aktiv''');



  while not QuerryBackupper.Eof do
  begin

    LReccord := QuerryBackupper.FieldByName('id').AsInteger;

    LStatus := QuerryBackupper.FieldByName('backupname').AsString;//LStatus
    LPfadFrom:= QuerryBackupper.FieldByName('pfad').AsString;
    LPfadTo:= QuerryBackupper.FieldByName('Pfad_export').AsString;
    LAddDate := QuerryBackupper.FieldByName('add_date').AsBoolean;
    LReplaceFolder := QuerryBackupper.FieldByName('replace_folder').AsBoolean;
    LAddBackupString := QuerryBackupper.FieldByName('add_backup_string').AsBoolean;
    Application.ProcessMessages;

    lProcessStatus.Caption := 'Starte mit der Archivierung...';
    //Strings in Arrays
    Setlength(FaStatus,length(FaStatus)+1);
    FaStatus[Length(FaStatus)-1] := Lstatus;//Backupname
    Setlength(FaPfad,length(FaPfad)+1);
    FaPfad[Length(FaPfad)-1] := LPfadFrom;//Pfad
    Setlength(Fapfadto,length(Fapfadto)+1);
    Fapfadto[Length(Fapfadto)-1] := LPfadTo;//Pfad Export
    //Boolean als Arrays
    Setlength(FaAddDate,length(FaAddDate)+1);
    FaAddDate[Length(FaAddDate)-1] := LAddDate;//add_date
    Setlength(FaReplaceFolder,length(FaReplaceFolder)+1);
    FaReplaceFolder[Length(FaReplaceFolder)-1] := LReplaceFolder;//replace Folder
    Setlength(FAddBackupString,length(FAddBackupString)+1);
    FAddBackupString[Length(FAddBackupString)-1] := LAddBackupString;//Pfad Export

    QuerryBackupper.Next;
  end;

  adoConBackupper.Connected := false;

  for i := 0 to LRecordCount -1 do
    begin
      Lstatus := FaStatus[i];
      LPfadFrom := FaPfad[i];
      LPfadTo := Fapfadto[i];

      LAddDate := FaAddDate[i];
      LReplaceFolder := FaReplaceFolder[i];
      LAddBackupString := FAddBackupString[i];

      FFileCountFrom := TMyDaten.CountFiles(LPfadFrom);
      //ist Einstellung AddDate true dann Datum erstellen
      if LAddDate = true then
       LDateNow := DateToStr(now);

      // is Einstellung auf true, dann wird in exportpfad'backup hinzugefügt'
      if LAddBackupString = true then
        LBackupString := '- Backup';

      //LPfadTo :=LPfadTo + LBackupString + '-' + LStatus + LDateNow;
      LPfadTo :=LPfadTo + '\' + LStatus + LBackupString + LDateNow;//pfad zu lang


      LThread := MyThread.Create(true);
      LThread.GPfadFrom := LPfadFrom;
      LThread.GFadTo := LPfadTo;
      LThread.Start;

     repeat
       FileCountTo := TMyDaten.CountFiles(LPfadTo); //ermittelt OrdnerZahl
        Progressbar1.Position := FileCountTo;
        Application.ProcessMessages;
      until FileCountTo = FFileCountFrom;
     ProgressBar1.Position:= 0;
      Application.ProcessMessages;
    end;//for i
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
  if Height > 150 then
  begin
    Timer2.Enabled := false;
    StartingProcess;
  //
  end
   else
    begin
      LockWindowUpdate(Handle);
      try
        Height := Height + 5;
        top := Screen.WorkAreaHeight - Height;
        //top := Screen.Height - Height;
      finally
        Lockwindowupdate(0);
      Application.BringToFront;
      end;
    end;
end;

end.
Ich will das das Programm die pfade aus der Datenbank liest und alle nach und Kopiert und den Fortschritt in eine Progressbar anzeigt.

Luckie 27. Nov 2010 16:06

AW: Daten Kopieren mit Thread?
 
Eine Möglichkeit wäre, dass du dir vom Thread am Ende eine Nachricht schicken lässt. Oder du nutzt die Methode WaitFor aus der Thread Klasse.

SirThornberry 27. Nov 2010 18:14

AW: Daten Kopieren mit Thread?
 
oder wie ziemlich weit oben schon erwähnt wurde das OnTerminate des Threads verwenden.

Sir Rufo 27. Nov 2010 23:37

AW: Daten Kopieren mit Thread?
 
Oder man gibt dem Thread eine Queue. In die platziert man die Arbeitsaufträge.

Der Thread arbeitet diese nun einfach ab, bis die Warteschlange leer ist und legt sich dann schlafen (Suspended).
Wird ein neuer Auftrag in die Queue geschoben, weckt dieses Ereignis den Thread wieder auf.
Nach jedem Arbeitsauftrag kann der Thread noch einen Event abschicken, das der Auftrag xy abgearbeitet ist.

Deine Umsetzung mit dem Thread ist irgendwie so eine halbtags Sache zwischen Thread und doch nicht Thread. Der Thread kopiert die Daten und die Form kontrolliert wieviele Daten kopiert wurden.
Das ist nicht nur vom Ablauf suboptimal, sondern extrem ungeschickt.

Der Thread kann die Form auch informieren, ob er fertig ist, und zwischendurch den aktuellen Status (wieviele Dateien müssen noch, wieviele sind schon, wie heißt die aktuelle Datei die kopiert wird).
In der Form brauche ich keine Schleife, keinen Timer, sondern reagiere nur auf Events.

Hier wird quasi genau sowas gerade auch besprochen

WizoHulk 4. Dez 2010 01:28

AW: Daten Kopieren mit Thread?
 
Hallo Leute,

ich habe jetzt ein Thread das mir Ordner von a nach b kopiert.
wenn es nur ein Satz mit Herkunftpfad und Zielpfad ist, klappt das ja super, bloß ic hhabe einen Array von Strings die nach und nach in dem Thread abgearbeitet werden sollen.
Habe es mit einer Schleife versucht, aber das haut nicht hin, er startet immer erst den Thread wenn die Procedure beendet ist.
Hat jemand eine Idee wie man das beheben kann?

Luckie 4. Dez 2010 02:24

AW: Daten Kopieren mit Thread?
 
Zitat:

Zitat von WizoHulk (Beitrag 1066036)
Hat jemand eine Idee wie man das beheben kann?

Ohne Code kann man da schwer was zu sagen. ber ich würde das Array als Property an das Threadobjekt übergeben.

Sir Rufo 4. Dez 2010 08:52

AW: Daten Kopieren mit Thread?
 
Obwohl ich ja dafür immer eine WorkQueue verwenden würde.

Dann ist es völlig egal, zu welchem Zeitpunkt die Anwendung eine Aktion anfordert.
Ob in einer Schleife aus einem Array oder durch einen Tastendruck vom User.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:49 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz