AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Dateien performant mit Callback kopieren
Thema durchsuchen
Ansicht
Themen-Optionen

Dateien performant mit Callback kopieren

Ein Thema von DieDolly · begonnen am 2. Aug 2018 · letzter Beitrag vom 3. Aug 2018
Antwort Antwort
Seite 4 von 4   « Erste     234   
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#31

AW: Dateien performant mit Callback kopieren

  Alt 3. Aug 2018, 15:22
Ich nutze ja schon CopyFileEx mit CallBack (seit eben).
Ich verstehe nur nicht, wie ich eine globale Variable hochzählen muss, damit auch zwei oder mehr CopyFileEx-Aufrufe hintereinander die kopierten Datenmenge richtig hochzählen.

Aktuell ist es so. Komischerweise wird, wenn die Zweite Datei anfängt zu kopieren, die globale Variable OverallBytesCopied auf 0 zurückgesetzt. Das mache ich nirgendwo selber!

Delphi-Quellcode:
procedure CopyCallBackTEST(TotalFileSize, TotalBytesTransferred, StreamSize, StreamBytesTransferred: Int64; dwStreamNumber, dwCallbackReason: DWORD; hSourceFile, hDestinationFile: THandle); stdcall;
begin
 if dwCallbackReason = CALLBACK_CHUNK_FINISHED then
  begin
   if not CancelCopy then
    begin
     TInterlocked.Add(OverallBytesCopied, TotalBytesTransferred - OverallBytesCopiedOld); // Kopierte Dateimenge hoch zählen ***

     MainForm.Caption := OverallBytesCopied.ToString + ' - ' + TotalBytesTransferred.ToString + ' - ' +
      (TotalBytesTransferred - OverallBytesCopiedOld).ToString + ' - ' + TotalFileSize.ToString;

     OverallBytesCopiedOld := OverallBytesCopied;
    end;
  end;
end;

// *** funktioniert mit einer Datei wunderbar. Sobald aber die zweite startet, fängt OverallBytesCopied wieder bei 0 an.

Result := CopyFileEx(PChar(Source), PChar(Dest), @CopyCallBackTEST, nil, @CancelCopy, 0);
Bei 2x 1 GB an Dateien wird OverallBytesCopied korrekt bis 1 GB hochgezählt. Danach tut sich nix mehr.
Dass diese Aret und Weise des Hochzählens funktioniert, beweist meine alte Kopiermethode und deren Callback. Das war im Prinzip dasselbe. Seit ich CopyFileEx und deren CallBack nutze, funktioniert das ab der 2. Datei nicht mehr.

"TotalBytesTransferred - OverallBytesCopiedOld" sind übrigens immer genau 1048576 Byte.

Ein Showmessage(OverallBytesCopied.ToString); vor CopyFileEx() zeigt beim ersten Durchgang 0 was korrekt ist. Beim zweiten 1 GB, was auch korrekt ist. Im Callback aber fängt die Zählung, warum auch immer, wieder bei 0 an.

Geändert von DieDolly ( 3. Aug 2018 um 17:03 Uhr)
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#32

AW: Dateien performant mit Callback kopieren

  Alt 3. Aug 2018, 17:11
Das mit CopyFileEx und CallBack lohnt sich alles nicht. Denn für die korrekte Berechnung für die kopierten Bytes muss man TotalBytesTransferred immer irgendwo zwischenspeichern und dann
Inc(OverallBytesCopied, TotalBytesTransferred - TotalBytesTransferredOld); aufrufen, damit man die korrekten Werte hochzählen kann.

Bei einem Thread ist das in Ordnung. Bei mehreren nicht. Dafür bräuchte man eine Art Wrapper für CopyFileEx oder so mit einem aufgebohrten CallBack, der auch ChunkBytesTransferred statt TotalBytesTransferred zurückgibt.

Und weil ich davon keine Ahnung habe, bleibe ich bei meinen alten Funktionen
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#33

AW: Dateien performant mit Callback kopieren

  Alt 3. Aug 2018, 18:01
nicht @DieDolly, also Offtopic:
Ich habe bereits viele Dinge gebencht, WinApi aus XP Generation war immer langsamer gegenüber Delphi Eigenkreationen.
Seit Windows 7 liegt beides auf Augenhöhe wobei bei vielen kleinen Dateien die Api meist schneller ist, je größer eine Datei ist, umso mehr kann in einer Eigenkreation herausgekitzelt werden. Ob sich der Mehraufwand lohnt, entscheidet jeder für sich selbst, Letzten Endes bin auch ich wieder bei der Api gelandet und mache mir über paar (zehn-)tausend ms mehr oder weniger keine Gedanken mehr.

Meine Benchs waren auch aussagekräftig, nicht das Datei X immer wieder nur aus Cache kopiert wurde, ne ne ne, immer schön brav mit Neustart und Warmlaufzeit des Systems gebencht.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#34

AW: Dateien performant mit Callback kopieren

  Alt 3. Aug 2018, 18:06
Ich habe das jetzt so geregelt, dass kleine Dateien mit CopyFileEx ohne Callback kopiert werden. Alles ab einer gewissen Größe mit meiner Eigenkreation und 50 MB Buffer.
Wenn meine Eigenkreation eine Datei abarbeiten soll die kleiner als der Buffer ist, so wird der Buffer mit der Dateigröße gleichgestellt.
Ich denke ich baue meine Eigenkreation, die hier aus dem Forum kommt, aber noch um, dass diese Fallunterscheidung in der Unit selber stattfindet.
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#35

AW: Dateien performant mit Callback kopieren

  Alt 3. Aug 2018, 18:13
@DieDolly, dafür das Du schreibst Dein Code sei alt, mein Delphi versteht den nicht, also Du scheinst auf dem Richtigen Wege zu sein.

Ps: Mir wurde letztens auf die Finger gehaun als ich Form.Caption aufruf, ich hatte es damals nicht so ganz verstanden da ich das eh nur zu Testzwecken drinnen hat war es mir in dem Moment Egal, vielleicht könnte sich dazu nochmal jemand äußern (Luckie evtl?)
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#36

AW: Dateien performant mit Callback kopieren

  Alt 3. Aug 2018, 18:22
Und weil ich davon keine Ahnung habe, bleibe ich bei meinen alten Funktionen
Falls Du es überlesen haben solltest, poste ich mal Code aus Link.
Zitat:
How to call CopyFileEx and let the callback update a progress bar

Question
Does anyone have an example of using CopyFileEx with a CopyProgressRoutine? I have created a function that takes the same parameters as the CopyProgressRoutine, but when I pass it using @ or Addr() I get a "Variable Required" error message.
Let's assume you call CopyFileEx and want the callback to update a progress bar. The callback cannot be an object's method but you can use the lpData parameter of CopyFileEx to pass any kind of data to the callback, e.g. a form reference. So, if you want to serve a progress form in the callback here's a little project that does the job.

Create a new Delphi project with two forms. Name the main form Form1 and save it as Unit1.pas. Name the second form ProgressForm and save it as Unit2.pas. Ensure that ProgressForm is not auto-created by the project. Set ProgressForm's FormStyle property to fsStayOnTop.

On the main form drop a TButton named CopyFileButton and a TOpenDialog component named OpenDialog. Create an OnClick event handler for the button with the following code.
Delphi-Quellcode:
procedure TForm1.CopyFileButtonClick(Sender: TObject);
begin
  if OpenDialog.Execute then
    DoFileCopy(OpenDialog.FileName, OpenDialog.FileName + '.bak')
end;
Zitat:
Somewhere above TForm1.CopyFileButtonClick in the implementation section of Unit1 add the following code:
Delphi-Quellcode:
function CopyCallback(TotalFileSize, TotalBytesTransferred, StreamSize,
  StreamBytesTransferred: Int64; dwStreamNumber, dwCallbackReason: DWORD;
  hSourceFile, hDestinationFile: THandle; progressform: TProgressForm ):
  DWORD; stdcall;
var
  newpos: Integer;
const
  PROCESS_CONTINUE = 0;
begin
  Result := PROCESS_CONTINUE;
  if dwCallbackReason = CALLBACK_CHUNK_FINISHED then
  begin
    newpos := Round(TotalBytesTransferred / TotalFileSize * 100);
    with progressform.Progressbar do
      if newpos <> Position then
        Position := newpos;
    Application.ProcessMessages;
  end;
end;

function DoFilecopy(const source, target: string): Boolean;
var
  progressform: TProgressForm;
begin
  progressform := TProgressform.Create(Form1);
  try
    progressform.Show;
    Application.ProcessMessages;
    Result := CopyFileEx(
      PChar(source), PChar(target), @CopyCallback,
      Pointer(progressform), @progressform.FCancel, 0
    );
 finally
   progressform.Hide;
   progressform.free;
 end;
end;
Zitat:
DoFileCopy set up the file copy operation and displays the progress dialog box (which we'll come to in a moment) and CopyCallback is the CopyProgressRoutine. This callback calculates the progress of the file copy and updates the progress bar on the progress form.

New for the progress form. Drop a TProgessBar named ProgressBar and a TButton named AbortButton on ProgressForm. Add a public Boolean field named fCancel to TProgressForm and add an OnClick event handler to AbortButton as follows:
Delphi-Quellcode:
procedure TProgressForm.AbortButtonClick(Sender: TObject);
begin
  fCancel := True;
end;
Zitat:
Add a reference to Unit2 in the uses clause of Unit1.

You can now compile and run the program. Click the button in the main form to display the open file dialog box. Select a file to copy – something largish, say 60MB should enable the progress dialog to display for long enough to see what's happening. OK the dialog box and the file copy begins and the progress dialog displays, updating the progress bar as the file copy proceeds. Try clicking the progress dialog's abort button to cancel the copy.

Tip revised and made to work correctly by DelphiDabbler.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#37

AW: Dateien performant mit Callback kopieren

  Alt 3. Aug 2018, 18:42
Falls Dich das Thema interessiert und Du Dich da etwas vertiefen möchtest, hier habe ich auch noch einen Lauffähigen Code entdeckt, man muss halt für Seine Zwecke dieses und jenes Anpassen damit man mehr Werte für GUI-Anzeige hat, aber generell ist das eine Super-Vorlage.
Damit kannst Du relativ rasch auch BlockRead/Write StreamRead/Write etc verwirklichen, ich mag das Gerüst, vielleicht Du auch?
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#38

AW: Dateien performant mit Callback kopieren

  Alt 3. Aug 2018, 18:42
Das Problem ist, dass mich die ProgressBar nicht interessiert.
Ich berechne die Position der ProgressBar anhand einer globalen Variablen OverallBytesCopied, die von mehreren Instanzen meiner Kopierfunktion aus mehreren Threads gefüttert wird.
CopyFileEx bietet im CallBack leider keinen Rückgabewert wie "ChunkBytesTransferred", was ich zu OverallBytesCopied dazuaddieren kann. Selber ausrechnen ist möglich, dann aber single-threadet.

Zitat:
ich mag das Gerüst, vielleicht Du auch?
Das ist genau die Vorlage die ich nutze. ich habe sie nur noch erweitert
Delphi-Quellcode:
   if ADestinationFile <> 0 then
    try
     // If the actual BufferSize is biger than the file size, set buffersize to filesize
     FileSizeSource := FileSize(ASourceFileName);
     if BufferSize > FileSizeSource then
      SetLength(Buffer, FileSizeSource)
     else
      SetLength(Buffer, BufferSize);

Geändert von DieDolly ( 3. Aug 2018 um 18:45 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#39

AW: Dateien performant mit Callback kopieren

  Alt 3. Aug 2018, 19:02
Das ist genau die Vorlage die ich nutze.
Na dann kann ja fast nichts schiefgehen

Was Dein Chunk Problem betrifft, das wirst Du per Api-Copy glaube ich nicht geregelt bekommen, da solltest Du auf BlockRead/Write StreamRead/Write umsatteln, numRead/numWritten sind dann wahrscheinlich Deine Kandidaten, oder Offset plus minus irgendwas...
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 4 von 4   « Erste     234   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:18 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