![]() |
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:
Bei 2x 1 GB an Dateien wird OverallBytesCopied korrekt bis 1 GB hochgezählt. Danach tut sich nix mehr.
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); 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. |
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 |
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. |
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. |
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?) |
AW: Dateien performant mit Callback kopieren
Zitat:
![]() Zitat:
Delphi-Quellcode:
procedure TForm1.CopyFileButtonClick(Sender: TObject);
begin if OpenDialog.Execute then DoFileCopy(OpenDialog.FileName, OpenDialog.FileName + '.bak') end; Zitat:
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:
Delphi-Quellcode:
procedure TProgressForm.AbortButtonClick(Sender: TObject);
begin fCancel := True; end; Zitat:
|
AW: Dateien performant mit Callback kopieren
Falls Dich das Thema interessiert und Du Dich da etwas vertiefen möchtest,
![]() Damit kannst Du relativ rasch auch BlockRead/Write StreamRead/Write etc verwirklichen, ich mag das Gerüst, vielleicht Du auch? |
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:
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); |
AW: Dateien performant mit Callback kopieren
Zitat:
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 06:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz