MD5-Hash mit Callback, Fortschritt, verbleibende Zeit, usw.
Verfasst: 14.03.2008 15:19
Hallo!
Basierend auf Kiffi's Code habe ich eine Prozedur geschrieben, die von einer beliebigen Datei MD5 Prüfsummen ermittelt.
Das Problem: Ist die Datei mehere MB oder sogar GB groß, kommt man mit MD5FileFingerprint() nicht sehr weit. Der Befehl ist unflexibel und bietet keinerlei RÜckmeldung während der Operation.
Anders meine Prozedur MD5FileFingerprintCallback(). Sie bietet
file$
Die Datei, von der der MD5 Hash ermittelt werden soll.
*callback
Adresse des Callbacks. Wenn *callback=0, dann wird die Callbackfunktion deaktiviert. Das Callback muss folgendes Format haben:
myCallback(file.s, progress.l, speed.l, remainingTime.l, elapsedTime.l)
Der Callback kann einen Wert ungleich null zurückgeben, um die Operation abzubrechen.
callCallbackEvery
Zeitabstand in Millisekunden, in der der Callback aufgerufen werden soll. Nützlich, um ein Flackern der Gadgets zu verhindern. Ein Flackern kann z. B. dann entstehen, wenn ein Gadget zu schnell upgedated wird.
bufferSize
Größe in Bytes für den angegeben Buffer, der allokiert wird. Ein größerer Buffer kann eine Verkürzung der Bearbeitungszeit zur Folge haben.
Rückgabewert
Es wird der Hashstring zurückgegeben oder ein Leerstring, falls die Operation fehlschlug.
Edit:
habe mein Problem gefunden. Hatte den Fortschritt als Float-Variable an den Callback übergeben; CallFunctionFast() unterstützt aber keine Floats als Rückgabewert oder Parameter. Das heißt: Viel Spaß beim Benutzen der Prozedur!
Basierend auf Kiffi's Code habe ich eine Prozedur geschrieben, die von einer beliebigen Datei MD5 Prüfsummen ermittelt.
Das Problem: Ist die Datei mehere MB oder sogar GB groß, kommt man mit MD5FileFingerprint() nicht sehr weit. Der Befehl ist unflexibel und bietet keinerlei RÜckmeldung während der Operation.
Anders meine Prozedur MD5FileFingerprintCallback(). Sie bietet
- Fortschritt in Prozent
- verbleibende Zeit
- verstrichene Zeit
- Geschwindigkeit in Byte pro Sekunde (mit der beigefügten bytecalc()-Prozedur von mir kann dies bequem in höhrere Einheiten umgerechnet werden)
- Abbruchmöglichkeit, falls Callback einen Wert ungleich null zurückgibt
Code: Alles auswählen
#file="D:\Dateien\CD Image.img"
Procedure.s bytecalc(byte.q, NbDecimals.l=0)
If byte < 1024
If byte < 0
ProcedureReturn "0 Byte"
EndIf
ProcedureReturn Str(byte)+" Byte"
ElseIf byte >= 1<<60
ProcedureReturn StrD(byte/1<<60, NbDecimals)+" EB"
ElseIf byte >= 1<<50
ProcedureReturn StrD(byte/1<<50, NbDecimals)+" PB"
ElseIf byte >= 1<<40
ProcedureReturn StrD(byte/1<<40, NbDecimals)+" TB"
ElseIf byte >= 1<<30
ProcedureReturn StrD(byte/1<<30, NbDecimals)+" GB"
ElseIf byte >= 1<<20
ProcedureReturn StrD(byte/1<<20, NbDecimals)+" MB"
Else
ProcedureReturn StrD(byte/1024, NbDecimals)+" KB"
EndIf
EndProcedure
Procedure myCallback(file.s, progress.l, speed.l, remainingTime.l, elapsedTime.l)
SetGadgetText(3, "Entire progress: "+Str(progress)+"%")
SetGadgetText(4, "Speed: "+bytecalc(speed)+"/sec ("+Str(speed)+" Byte/s)")
SetGadgetText(5, FormatDate("Elapsed: %hhh%iim%sss", elapsedTime)+#CRLF$+FormatDate("Remaining: %hhh%iim%sss", remainingTime))
SetGadgetState(0, Int(progress))
While WindowEvent() : Wend
ProcedureReturn 0 ; Return 0 to continue, 1 to abort
EndProcedure
Procedure.s MD5FileFingerprintCallback(file$, *callback=0, callCallbackEvery=1000, bufferSize=4096)
; Callback format: myCallback(file.s, progress.l, speed.l, remainingTime.l, elapsedTime.l)
Protected startTime.l=Date(), file.l=ReadFile(#PB_Any, file$), hash.s
If file
Protected *buffer=AllocateMemory(bufferSize)
If *buffer
Protected fingerprint=ExamineMD5Fingerprint(#PB_Any)
If fingerprint
Protected progress.l, refresh.l, elapsed.l, speed.l, remaining.l
While Not Eof(file)
NextFingerprint(fingerprint, *buffer, ReadData(file, *buffer, bufferSize))
If *callback And ElapsedMilliseconds() > refresh
If Lof(file) ; to avoid division by zero if filesize is 0 bytes
elapsed=Date()-startTime
progress=Round(Loc(file)/Lof(file)*100, #PB_Round_Nearest)
If elapsed ; to avoid division by zero
speed=Round(Loc(file)/elapsed, #PB_Round_Nearest)
If speed ; prevent division by zero
remaining=Round((Lof(file)-Loc(file))/speed, #PB_Round_Nearest)
EndIf
EndIf
EndIf
If CallFunctionFast(*callback, file$, progress, speed, remaining, elapsed)
Break
EndIf
refresh=ElapsedMilliseconds()+callCallbackEvery
EndIf
Wend
hash=FinishFingerprint(fingerprint)
EndIf
FreeMemory(*buffer)
EndIf
CloseFile(file)
EndIf
ProcedureReturn hash
EndProcedure
If OpenWindow(0, 0, 0, 400, 160, GetFilePart(#file)+" "+bytecalc(FileSize(#file), 1), #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))
ProgressBarGadget(0, 10, 30, 250, 30, 0, 100)
TextGadget (3, 10, 10, 250, 20, "")
TextGadget (4, 10, 70, 250, 20, "")
TextGadget (5, 100,110, 200, 50, "")
Define md5$=MD5FileFingerprintCallback(#file, @myCallback(), 250)
MessageRequester("MD5FileFingerprintCallback()", "finished! has code:"+#CRLF$+md5$)
EndIf
Die Datei, von der der MD5 Hash ermittelt werden soll.
*callback
Adresse des Callbacks. Wenn *callback=0, dann wird die Callbackfunktion deaktiviert. Das Callback muss folgendes Format haben:
myCallback(file.s, progress.l, speed.l, remainingTime.l, elapsedTime.l)
Der Callback kann einen Wert ungleich null zurückgeben, um die Operation abzubrechen.
callCallbackEvery
Zeitabstand in Millisekunden, in der der Callback aufgerufen werden soll. Nützlich, um ein Flackern der Gadgets zu verhindern. Ein Flackern kann z. B. dann entstehen, wenn ein Gadget zu schnell upgedated wird.
bufferSize
Größe in Bytes für den angegeben Buffer, der allokiert wird. Ein größerer Buffer kann eine Verkürzung der Bearbeitungszeit zur Folge haben.
Rückgabewert
Es wird der Hashstring zurückgegeben oder ein Leerstring, falls die Operation fehlschlug.
Edit:
habe mein Problem gefunden. Hatte den Fortschritt als Float-Variable an den Callback übergeben; CallFunctionFast() unterstützt aber keine Floats als Rückgabewert oder Parameter. Das heißt: Viel Spaß beim Benutzen der Prozedur!