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/)
-   -   Dateien performant mit Callback kopieren (https://www.delphipraxis.net/197377-dateien-performant-mit-callback-kopieren.html)

DieDolly 2. Aug 2018 16:44

Dateien performant mit Callback kopieren
 
Mit welcher Technik ließt und schreibt man am schnellsten / besten Daten von und auf eine Festplatte, sodass ich in einer Callbackprozedur zeitgleich Daten wie bereits kopierte Bytes, Dateigröße und Dateiname abfragen kann?

Ich bin über jegliche Hilfe dankbar.

KodeZwerg 2. Aug 2018 17:12

AW: Dateien performant mit Callback kopieren
 
Je nachdem um was für Inhalt es sich handelt gäbe es verschiedene Lösungen.

Geht es nur darum Datei A nach Datei B zu kopieren, Api oder TFileStreams.
Über Api kann ein Windows-Kopieren Dialog eingeblendet werden.
Über TFileStream liegt alles bei Dir. Damit habe ich gute Erfahrungen sammeln können bei ca 64kb chunks.
Benötigt man auch noch spezielle Attribute, oder Dateiberechtigungen, ist erheblich mehr Aufwand nötig.

DieDolly 2. Aug 2018 17:22

AW: Dateien performant mit Callback kopieren
 
Es geht nur um Datei von A nach B.
Jedoch komplett ohne Windows-Dialoge. Nur Eigenbau.

KodeZwerg 2. Aug 2018 17:33

AW: Dateien performant mit Callback kopieren
 
Ein Möglicher Ansatz, nur hier im Editor erstellt als Vorwarnung....
Delphi-Quellcode:
Procedure DollyCopy(const SourceFilename, TargetFilename: string);
var
  Source, Target: TFileStream;
Begin
  Source := TFileStream.Create(SourceFilename, fmOpenRead);
  Try
    Target := TFileStream.Create(TargetFilename, fmOpenWrite OR fmCreate);
    Try
      Target.CopyFrom(Source, Source.Size);
    Finally
      Target.Free;
    End;
  Finally
   Source.Free;
  End;
End;
Noch wird nichts geprüft, noch wird alles in einem Rutsch erledigt, das soll lediglich die Basics verdeutlichen.
Es gibt auch zig andere Möglichkeiten.... so in etwa sieht meine auch aus, nur das ich nicht alles auf einmal lese/schreibe.

JanWe 2. Aug 2018 17:34

AW: Dateien performant mit Callback kopieren
 
also ich hab das immer so gemacht:
Delphi-Quellcode:
Datei1Str := 'C:\Datei.txt';
Datei2Str := 'D:\Datei.txt';

if FielExists(Datei) then
ErfolgBool := CopyFile (pchar(Datei1Str),pchar(Datei2Str), TRUE );
// wenn bei Parameter 3 True gesetzt ist, wird abgebrochen, falls die Datei bereits existiert
//bei FALSE wird die Datei gnadenlos überschrieben.

KodeZwerg 2. Aug 2018 17:51

AW: Dateien performant mit Callback kopieren
 
Delphi-PRAXiS hat auch Beispiele wenn man sucht ^_^
Da ist es mit BlockRead/Write realisiert worden.

edit:
Ps: Am performantesten ist es so wenig wie möglich in GUI darzustellen, am schlimmsten wäre zum Beispiel eine ProgressBar die jedes Byte hochzählt.

himitsu 2. Aug 2018 20:52

AW: Dateien performant mit Callback kopieren
 
Ein gibt garnichts, was am Performantesten ist.

* wie viel wird kopiert (Anzahl und Größe)
* von wo nach wo wird kopiert (HDD, SDD, SD, NetShare, ...)
* wie viel RAM ist frei (da alles bissher hier genannte mit FileCache kopiert)
* wie sind die Controller/Treiber von Quelle und Ziel eingestellt (mit oder ohne Cache ... z.B. bei externen Datenträgern für "schnelles" entfernen)
* ...

Je nach Bedinungen ist etwas anderes performanter.
* mit oder ohne Lesecache kopieren (Cache im Controller und RAM) und wenn ja, mit wieviel
* mit Schreibcache kopieren oder ohne FileCache im RAM
* direkt auf die Platte oder nur in Cache (pass through)
* bei Netzwerken kann es eventuell schneller sein, auch noch Multithreaded zu arbeiten, also mehrere Dateien/Dateiteile gleichzeitig übertragen (wenn die Übertragung eines einzelen Kanals limitiert ist)
* ...

p80286 2. Aug 2018 21:41

AW: Dateien performant mit Callback kopieren
 
Was hast Du vor?
Wenn Du selbst kopierst, kennst Du Dateinamen und Dateigröße, also warum abfragen?
Du könntest mit mehreren Threads die Dateien kopieren, aber wenn das auf nur einer Festplatte stattfinden soll, ist das eher kontraproduktiv. Sei's drum, Du kannst jeden Thread eine Message mit dem aktuellen Stand des Kopiervorgangs schicken lassen.

Gruß
K-H

KodeZwerg 3. Aug 2018 05:47

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von himitsu (Beitrag 1409572)
Ein gibt garnichts, was am Performantesten ist.

Zumindest nannte ich eine tödlich-performante Variante, jedes Byte in GUI darstellen, da verlagert sich dann der Flaschenhals nach GUI.
Zitat:

Zitat von p80286 (Beitrag 1409574)
Sei's drum, Du kannst jeden Thread eine Message mit dem aktuellen Stand des Kopiervorgangs schicken lassen

Solange es Lokal "fest verkabelt" und nicht über LAN (o.ä.) stattfindet, Rate ich davon ab, Flaschenhals ist bei Kopierprozessen idR der BUS.


Meine Erfahrungen mit selbst gezüchteten Kopiertechniken:
  • Eine non-Cached Variante verliert idR bei Performance-Tests immer.
  • Eine multi-Thread Variante scheitert meist am BUS Flaschenhals, da kann man auch die Kerne im Vorfeld auslesen und dementsprechend Threads verteilen, es passt nunmal nur eine Gewisse Menge an Daten zwischen den BUS.
  • eine cached Variante mit 4kb ist sehr flott, bei 64kb blöcken habe ich in meinem System die beste Kopier-Rate.
  • Kopier-Programme die im Vorfeld verbaute Caches ermitteln kenne ich persönlich noch nicht, das wäre mal eine Herausfordernung.
  • Für eine ProgressBar kommt aus meiner Sicht nur eine Prozent-Anzeige in Frage, ich selbst nutze eine 5% Variante, habe noch keine Nachteile feststellen können. (alle +5% aktualisiert sich meine GUI)
  • Ich selbst erstelle/nutze einen Kopier-Thread, damit GUI entlastet wird.

Sinnvolle Anzeigen für GUI:
  • ProgressBars für kompletten Vorgang und aktueller Datei (für Multi-Copy)
  • Labels für alle Bytes, kopierte Bytes; dazu vielleicht noch ein Label mit Rest-Kopier-Dauer?
  • Label für Dateinamen (bei Multi-Copy erscheint bei mir noch ein Label mit Pfad)
  • Abbrechen Knopf

Sinnvolle non-Visual Dinge:
  • Hash/CRC Kontrolle zum verifizieren der Daten.
  • Für cache Varianten könnten hier zusätzliche Manipulatoren eingeplant werden. Komprimierung/Verschlüsselung zum Beispiel. Je nach Sinn und Zweck.

API 3. Aug 2018 08:20

AW: Dateien performant mit Callback kopieren
 
Mit CopyFileEx()?

http://delphidabbler.com/tips/160

himitsu 3. Aug 2018 08:43

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zumindest nannte ich eine tödlich-performante Variante
Tödlich ist das richtige Wort.

Versuche mal mit sowas mehrere GB an Daten zu kopieren.
Windows bevorzugt per Standard den FileCache, kopiert durch den FileCache und da der LeseCache auch nach dem vollständigen Schreiben erhalten bleibt, schmeißt es somit ALLE Programme aus dem RAM in die PageFile und dein System wird sowas von ausgebremst, dass es richtig Spaß macht.

Bei FileStreams könntest DU wenigstens noch angeben, dass es sich um sequentielle Zugriffe handelt, damit Windows den Cache entsprechend optimieren könnte (wenn es das mal macht), aber da ist es einfacher die Kopierfunktionen der WinAPI zu nutzen, wo dessen Entwickler sowas hoffentlich beachtet haben.

EWeiss 3. Aug 2018 09:00

AW: Dateien performant mit Callback kopieren
 
Ach Leute Copy und vergleichbares, verstehe die Diskussion nicht.
Zitat:

Ein gibt garnichts, was am Performantesten ist.
Performanter als das System Daten kopiert gibt es eh nicht.
Und welche variante von Copy man verwendet ist letztendlich uninteressant.

gruss

DieDolly 3. Aug 2018 12:22

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von himitsu (Beitrag 1409590)
Zitat:

Zumindest nannte ich eine tödlich-performante Variante
Tödlich ist das richtige Wort.

Versuche mal mit sowas mehrere GB an Daten zu kopieren.
Windows bevorzugt per Standard den FileCache, kopiert durch den FileCache und da der LeseCache auch nach dem vollständigen Schreiben erhalten bleibt, schmeißt es somit ALLE Programme aus dem RAM in die PageFile und dein System wird sowas von ausgebremst, dass es richtig Spaß macht.

Bei FileStreams könntest DU wenigstens noch angeben, dass es sich um sequentielle Zugriffe handelt, damit Windows den Cache entsprechend optimieren könnte (wenn es das mal macht), aber da ist es einfacher die Kopierfunktionen der WinAPI zu nutzen, wo dessen Entwickler sowas hoffentlich beachtet haben.

Ich habe gerade eben mal mit CreateFile und alten Dateizugriffsfunktionen geprüft, ob es einen Unterschied macht FILE_FLAG_NO_BUFFERING zu nutzen oder nicht.
Mit FILE_FLAG_NO_BUFFERING dauert das erste Kopieren einer 1 GB Datei von E nach E 30 Sekunden. Danach Wieder 30 Sekunden.
Ohne den NO_Buffering-Parameter erst 30 Sekunden und danach wenn überhaupt eine Sekunde.

Würde das System theoretisch sehr viel langsamer werden wenn ich 25 x 1 GB ohne den No-Buffering-Parameter kopiere?

himitsu 3. Aug 2018 12:49

AW: Dateien performant mit Callback kopieren
 
Wie gesagt, was "optimaler" ist, das hängt von den Umweltbedingungen ab.

Und es gibt einen Unterschied ob das Kopieren "gefühlt" schnell ist, aber im Hintergrund noch weiterläuft, weil es nur in den Cache geschrieben wurde und der dann verzögert erst auf der Platte landet ... das merkst du dann, wenn du noch mehr kopierst.
Das "komplette" Schreiben dauert hierbei so oder so durchschnittlich gleich lang.

ABER, wenn es durch den FileCache den RAM "überfüllt" und du mehr kopierst, als RAM frei ist, dann werden andere Dinge ausgebremst und auch das Kopieren wird ab diesem Zeitpunkt langsamer und das sogar langsamer als ohne FileCache, also wenn man dessen Behandlung ganz umgehen würde.



Beim blosen Kopieren kann das Kopieren mit FileCache "gefühlt" schneller sein, aber insgesamt wird immer irgendwas ausgebremst, sobald nicht genügend RAM frei ist.

DieDolly 3. Aug 2018 12:54

AW: Dateien performant mit Callback kopieren
 
Verständlich erklärt. Eigentlich kann man sogar festhalten, dass es für Netbooks vom alten Schlag besser ist ohne Buffer zu kopieren. Denn die haben ohnehin nicht viel RAM.

Mavarik 3. Aug 2018 13:10

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von EWeiss (Beitrag 1409592)
Performanter als das System Daten kopiert gibt es eh nicht.

Getestet oder nur geschätzt?

EWeiss 3. Aug 2018 13:16

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von Mavarik (Beitrag 1409632)
Zitat:

Zitat von EWeiss (Beitrag 1409592)
Performanter als das System Daten kopiert gibt es eh nicht.

Getestet oder nur geschätzt?

Ich denke ist wohl abhängig von vielen Dingen.. Hardware, System, Software.
Sollte die Software schneller sein beim kopieren als das System selbst? Möchte ich bezweifeln.

gruss

Mavarik 3. Aug 2018 13:24

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von EWeiss (Beitrag 1409633)
Sollte die Software schneller sein beim kopieren als das System selbst? Möchte ich bezweifeln.

Also geschätzt.

Ich denke, das eine optimierte Software schnelle sein kann als das System. Der System copy process muss sehr variable und auf viele Faktoren "achten"...

Ich kann mich gut daran erinnern, dass es immer Software gab, die abhängig von der Festplatte ausgerechnet hat wann und wie schnell die Festplatte sich dreht und genau ausgerechnet hat, wann ein Track in einer Umdrehung gelesen werden kann. (Bei Floppy's waren da die größte Unterschiede).

Ich denke, wenn ich einen großen Block RAM reserviere (Physikalisch nicht über die Swap Datei) und dann in einem Rutsch 1GB lade und schreibe ohne jeden test ob Festplatte voll usw. dann ist das schneller als ein Copy vom System.

Aber getestet hab ich es auch nicht (in letzter Zeit)…

EWeiss 3. Aug 2018 13:27

AW: Dateien performant mit Callback kopieren
 
Zitat:

Also geschätzt.
Nein. Ich denke das ist logisch.. (aber desweiteren geschätzt. Ja ;) )
Wie gesagt es gibt viele Faktoren.. Einer der größten mag dein Virenscanner sein ;)

gruss

DieDolly 3. Aug 2018 13:37

AW: Dateien performant mit Callback kopieren
 
Wenn ich ohne Buffering von Windows und einer Buffergröße von 10 MB bei ReadFile eine 1 GB-Datei kopiere, dauert das rund 30 Sekunden.
Mit 256 KB Buffer 40 Sekunden.
Mit einem 100 MB Buffer 22 Sekunden - genau so schnell wie Windows.

Aber bei 100 MB merkt man, dass die ProgressBar sich beim Aktualisieren anders verhält. Es werden keine kleinen Sprünge mehr gemacht sondern jede Sekunde ein großer.
Ein 50 MB Buffer ist auch OK und eine 1 GB Datei ist nach 22 bis 23 Sekunden kopiert.

Wenn man ReadFile und WriteFile nimmt, dann ist ein 100 MB Buffer am schnellsten. je kleiner, desto länger dauert es.
Ich lese von einer mechanischen HDD und schreibe auf genau dieselbe für meine Tests.

Der beste Buffer scheint also irgendwo zwischen 30 und 50 MB zu liegen. jedenfalls für HDDs. Bei guten SSDs kann man meiner Meinung nach bei 100 MB anfangen.

Mavarik 3. Aug 2018 13:40

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von EWeiss (Beitrag 1409635)
Nein. Ich denke das ist logisch..

Nöö, das ist alles andere als logisch... Abgesehen von kopieren...

Schau mal hier - OK andere Aufgabenstellung.

Natives lesen ist langsamer als aus einer Datenbank - also ich hätte gewettet das der Datenbankoverhead das ganze viel langsamer macht.

EWeiss 3. Aug 2018 13:42

AW: Dateien performant mit Callback kopieren
 
[OT]
Zitat:

dass die ProgressBar sich beim Aktualisieren anders verhält
Man sollte nur zulassen das sich die Progressbar aktualisiert wenn sich die Daten verändert haben der Performance wegen.
Ob du das tust weis ich leider nicht.

Aber hier ein Beispiel.

Delphi-Quellcode:
    Progress := trunc(100 * (Bass_ChannelGetPosition(Channel, BASS_POS_BYTE) / Bass_ChannelGetLength
          (Channel, BASS_POS_BYTE)));

    if (ProgressBar.Value <> Progress) then
      ProgressBar.Value := Progress;
[/OT]

Zitat:

Abgesehen von kopieren...
Und darum ging es mir.. also doch logisch :)

gruss

Mavarik 3. Aug 2018 13:43

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von DieDolly (Beitrag 1409637)
Der beste Buffer scheint also irgendwo zwischen 30 und 50 MB zu liegen. jedenfalls für HDDs. Bei guten SSDs kann man meiner Meinung nach bei 100 MB anfangen.

Das Buffer solle immer aligned sein und zur Sektor-Größe passen.

Siehe

Mavarik 3. Aug 2018 13:47

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von DieDolly (Beitrag 1409637)
Wenn ich ohne Buffering von Windows und einer Buffergröße von 10 MB bei ReadFile eine 1 GB-Datei kopiere, dauert das rund 30 Sekunden.
Mit 256 KB Buffer 40 Sekunden.
Mit einem 100 MB Buffer 22 Sekunden - genau so schnell wie Windows.

Dazu hätte ich gerne mal Dein Testprogramm...

DieDolly 3. Aug 2018 13:48

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von Mavarik (Beitrag 1409642)
Zitat:

Zitat von DieDolly (Beitrag 1409637)
Der beste Buffer scheint also irgendwo zwischen 30 und 50 MB zu liegen. jedenfalls für HDDs. Bei guten SSDs kann man meiner Meinung nach bei 100 MB anfangen.

Das Buffer solle immer aligned sein und zur Sektor-Größe passen.

Da man ja nie weiß wie groß der Sektor einer Festplatte ist, denn es gibt ja tausende Verschiedene Platten, und 50 MB irgendwo ein Vielfaches von 512, 1024, 2048 oder 4096 ist, macht man da mit 50 MB was falsch?

Zitat:

Man sollte nur zulassen das sich die Progressbar aktualisiert wenn sich die Daten verändert haben der Performance wegen.
Sowas ist ein Muss.

sakura 3. Aug 2018 13:51

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von DieDolly (Beitrag 1409645)
Da man ja nie weiß wie groß der Sektor einer Festplatte ist, denn es gibt ja tausende Verschiedene Platten, und 50 MB irgendwo ein Vielfaches von 512, 1024, 2048 oder 4096 ist, macht man da mit 50 MB was falsch?

Ähm... vieles. Und die Sektorengröße kann man schließlich einfach ermitteln. Einfach mal in der DP suchen.

Aber ich verstehe nicht, warum Du nicht die Windows-Hausmittel nutzt, die sind i.A. sehr performant und darauf optimiert sich an die jeweiligen System anzupassen.

...:cat:...

DieDolly 3. Aug 2018 13:52

AW: Dateien performant mit Callback kopieren
 
Eine Datei in einem Rutsch mit CopyFile zu kopieren ist doch zu einfach.
Was mich an der Sache interessiert ist der CallBack und immer auf dem Laufenden zu sein, wieviel gerade kopiert wurde.

EWeiss 3. Aug 2018 13:52

AW: Dateien performant mit Callback kopieren
 
Zitat:

Sowas ist ein Muss.
Nur ich sehe immer wieder das es viele halt nicht tun.. aber sei's drum.
War nur ein Tip.
Zitat:

Aber ich verstehe nicht, warum Du nicht die Windows-Hausmittel nutzt, die sind i.A. sehr performant und darauf optimiert sich an die jeweiligen System anzupassen.
:thumb:

gruss

DieDolly 3. Aug 2018 13:57

AW: Dateien performant mit Callback kopieren
 
Zitat:

Ähm... vieles. Und die Sektorengröße kann man schließlich einfach ermitteln. Einfach mal in der DP suchen.
Finde dazu genau nichts.

Könnt ihr mir vielleicht ein Beispiel zeigen was ihr mit Hausmitteln meint? Damit meine ich kein simples CopyFile.
Sondern irgendwas mit einem CallBack, sodass ich immer auf dem Laufenden bin und den Kopiervorgang auch von Außen abbrechen kann.

Aktuell nutze ich alte Windowsmittel, die viele verfluchen. Ich sag nur Block-Methoden.
Da ich hier aber eine Schleife habe, kann ich wann immer ich möchte abbrechen.

Edit
mein Problem mit dem CopyFileEx-Callback ist, dass ich nicht weiß wie ich die kopierten Bytes hochzählen kann.
Delphi-Quellcode:
TInterlocked.Add(OverallBytesCopied, ....); // TotalFileSize, TotalBytesTransferred, StreamSize, StreamBytesTransferred ?
Bei einer Datei könnte ich OverallBytesCopied := TotalBytesTransferred; schreiben. Aber bei mehreren geht das nicht denke ich.

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, ...);
    end;
  end;
end;

Result := CopyFileEx(PChar(Source), PChar(Dest), @CopyCallBackTEST, nil, @CancelCopy, 0);

p80286 3. Aug 2018 14:51

AW: Dateien performant mit Callback kopieren
 
Wenn Du schon weißt was Du willst, dann nutz es doch:
http://www.pinvoke.net/default.aspx/kernel32.CopyFileEx

Falls Du mehr Performance willst, dann mußt Du erst einmal alle möglichen Scenarien aufbauen, z.B. Copy auf ein und der selben Festplatte, copy von Festplatte1 auf Festplatte2 usw.
Und dann für jedes Deiner Scenarien eine eigene Routine schreiben.
(Ob da jetzt der (Daten)Bus oder der Festplatten-Controler der Flaschenhals ist, ist dann Thema für den 3.Grad)
Übrigens konnte man früher SCSI-Festplatten Vom SCSI-Controler kopieren lassen. Da ging die Luzy wirklich ab. War nur ein wenig aufwendig die Parameter richtig zu bestimmen. Und war nicht ganz trivial.:twisted:
Die beim Kopiervorgang eingesparte Zeit hat den Programmieraufwand nie aufgewogen.

Wenn Du nicht eine ganz spezielle Anwendung im Sinn hast, dann laß das Betriebssystem seine Arbeit machen.

Gruß
K-H

DieDolly 3. Aug 2018 15:22

AW: Dateien performant mit Callback kopieren
 
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.

DieDolly 3. Aug 2018 17:11

AW: Dateien performant mit Callback kopieren
 
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 :P

KodeZwerg 3. Aug 2018 18:01

AW: Dateien performant mit Callback kopieren
 
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.

DieDolly 3. Aug 2018 18:06

AW: Dateien performant mit Callback kopieren
 
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.

KodeZwerg 3. Aug 2018 18:13

AW: Dateien performant mit Callback kopieren
 
@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?)

KodeZwerg 3. Aug 2018 18:22

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von DieDolly (Beitrag 1409674)
Und weil ich davon keine Ahnung habe, bleibe ich bei meinen alten Funktionen :P

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.

KodeZwerg 3. Aug 2018 18:42

AW: Dateien performant mit Callback kopieren
 
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?

DieDolly 3. Aug 2018 18:42

AW: Dateien performant mit Callback kopieren
 
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);

KodeZwerg 3. Aug 2018 19:02

AW: Dateien performant mit Callback kopieren
 
Zitat:

Zitat von DieDolly (Beitrag 1409686)
Das ist genau die Vorlage die ich nutze.

Na dann kann ja fast nichts schiefgehen :thumb::thumb:

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...


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:28 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