![]() |
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. |
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. |
AW: Dateien performant mit Callback kopieren
Es geht nur um Datei von A nach B.
Jedoch komplett ohne Windows-Dialoge. Nur Eigenbau. |
AW: Dateien performant mit Callback kopieren
Ein Möglicher Ansatz, nur hier im Editor erstellt als Vorwarnung....
Delphi-Quellcode:
Noch wird nichts geprüft, noch wird alles in einem Rutsch erledigt, das soll lediglich die Basics verdeutlichen.
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; Es gibt auch zig andere Möglichkeiten.... so in etwa sieht meine auch aus, nur das ich nicht alles auf einmal lese/schreibe. |
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. |
AW: Dateien performant mit Callback kopieren
![]() 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. |
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) * ... |
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 |
AW: Dateien performant mit Callback kopieren
Zitat:
Zitat:
Meine Erfahrungen mit selbst gezüchteten Kopiertechniken:
Sinnvolle Anzeigen für GUI:
Sinnvolle non-Visual Dinge:
|
AW: Dateien performant mit Callback kopieren
|
AW: Dateien performant mit Callback kopieren
Zitat:
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. |
AW: Dateien performant mit Callback kopieren
Ach Leute Copy und vergleichbares, verstehe die Diskussion nicht.
Zitat:
Und welche variante von Copy man verwendet ist letztendlich uninteressant. gruss |
AW: Dateien performant mit Callback kopieren
Zitat:
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? |
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. |
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.
|
AW: Dateien performant mit Callback kopieren
Zitat:
|
AW: Dateien performant mit Callback kopieren
Zitat:
Sollte die Software schneller sein beim kopieren als das System selbst? Möchte ich bezweifeln. gruss |
AW: Dateien performant mit Callback kopieren
Zitat:
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)… |
AW: Dateien performant mit Callback kopieren
Zitat:
Wie gesagt es gibt viele Faktoren.. Einer der größten mag dein Virenscanner sein ;) gruss |
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. |
AW: Dateien performant mit Callback kopieren
Zitat:
Schau mal ![]() Natives lesen ist langsamer als aus einer Datenbank - also ich hätte gewettet das der Datenbankoverhead das ganze viel langsamer macht. |
AW: Dateien performant mit Callback kopieren
[OT]
Zitat:
Ob du das tust weis ich leider nicht. Aber hier ein Beispiel.
Delphi-Quellcode:
[/OT]
Progress := trunc(100 * (Bass_ChannelGetPosition(Channel, BASS_POS_BYTE) / Bass_ChannelGetLength
(Channel, BASS_POS_BYTE))); if (ProgressBar.Value <> Progress) then ProgressBar.Value := Progress; Zitat:
gruss |
AW: Dateien performant mit Callback kopieren
Zitat:
![]() |
AW: Dateien performant mit Callback kopieren
Zitat:
|
AW: Dateien performant mit Callback kopieren
Zitat:
Zitat:
|
AW: Dateien performant mit Callback kopieren
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. ...:cat:... |
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. |
AW: Dateien performant mit Callback kopieren
Zitat:
War nur ein Tip. Zitat:
gruss |
AW: Dateien performant mit Callback kopieren
Zitat:
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:
Bei einer Datei könnte ich OverallBytesCopied := TotalBytesTransferred; schreiben. Aber bei mehreren geht das nicht denke ich.
TInterlocked.Add(OverallBytesCopied, ....); // TotalFileSize, TotalBytesTransferred, StreamSize, StreamBytesTransferred ?
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); |
AW: Dateien performant mit Callback kopieren
Wenn Du schon weißt was Du willst, dann nutz es doch:
![]() 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 |
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:24 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