AW: DEC 5.2 String hashen?
Eine Frage hätte ich noch. Ich habe gerade mal beobachtet wie die "E/A Bytes (Lesen)" im Taskmanager aussieht nachdem ich mein Testprogramm starten.
Mit meinem aktuellen Code und einem <Stream>.LoadFromFile() geht der o.g. Wert direkt in die Höhe. Ich würde mal sagen dort steht dann Programmgröße + 200KB. Wenn ich folgenden Code verwende, dann passiert das nicht. Woran liegt das?
Delphi-Quellcode:
Wo ist also der Unterschied was den Wert "E/A Bytes (Lesen)" angeht zwischen den Zeilen unten?
aFileStream := TFileStream.Create(ParamStr(0), fmOpenRead or fmShareDenyWrite);
try // Get hash from stream end SetLength(s, 32 * SizeOf(Byte)); aFileStream.Position := aFileStream.Size - Length(s); aFileStream.Read(s[1], Length(s)); ShowMessage(s); finally aFileStream.Free; end;
Delphi-Quellcode:
Und: gibt es eine Lösung TBytesStream zu verwenden -ohne- dieses Problem im TaskManager? (TStringStream verursacht diese Anzeige übrigens auch)
// Verursaacht hohe (Programmgröße + ~100KB) "E/A Bytes (Lesen)" im Taskmanager
aByteStream := TBytesStream.Create; aByteStream.LoadFromFile(ParamStr(0)); // Verursacht dieses Problem nicht aFileStream := TFileStream.Create(ParamStr(0), fmOpenRead or fmShareDenyWrite); |
AW: DEC 5.2 String hashen?
In deinem Codebeispiel oben liest du nur 32 Bytes:
aFileStream.Read(s[1], Length(s)); in deinem Beispiel unten das ganze File aByteStream.LoadFromFile(ParamStr(0)); |
AW: DEC 5.2 String hashen?
Mh ok klingt logisch und einleuchtend jetzt wo ich da mal drauf gucke.
Was ich gerade auch sehe.. folgende Zeile erzeugt denselben Effekt im Taskmanager:
Delphi-Quellcode:
// Stringlänge auf Streamlänge setzen
SetLength(sHash, aFileStream.Size); |
AW: DEC 5.2 String hashen?
Genau der gleiche Grund, du verlangst u.U. viel Speicher.
|
AW: DEC 5.2 String hashen?
Ich habe das jetzt mal so gelöst. Ich bin von TStringStream weg, da es hier als Masochismus betitelt wurde.
Leider aber wieder hin zu AnsiString. Mit String bekomme ich nur Salat als Ergebnis. Es funktioniert, aber es ist bestimmt nicht perfekt.
Delphi-Quellcode:
Das Problem mit dem hohen Speicher bekomme ich leider nicht weg, da ich das SetLength nicht einfach weglassen kann :(
SetLength(s, aFileStream.Size - (32 * SizeOf(Byte)));
aFileStream.Read(s[1], Length(s)); s:= THashFunctions_Selftest.CalcHash(s); Result := s; |
AW: DEC 5.2 String hashen?
Naja, wenn Du 'nen Hash über 50 MB machen willst, musst Du auch die 50 MB einmal lesen.
Du wirst also immer einmal die Menge Speicher benötigen, die der Größer der EXE entspricht plus dem, was vom Programm ansonsten noch zum Ermitteln des Hashes benötigt wird. Egal welche Methode Du wählst: Um mindestens einmal alles Lesen wirst Du nicht herumkommen. |
AW: DEC 5.2 String hashen?
Wenn du den Hash selbst ermitteln musst, dann empfehle ich dir dies Stück für Stück zu tun.
Ich hatte mal Code gepostet, welcher gleich alles las. Das ist natürlich für extrem grosse Files dumm. [Aber für die meisten "normalen Fälle" ausreichend.] Wenn du über das ganze File hashen willst, dann nimm doch eine vorgefertigte Methode, zum Beispiel
Delphi-Quellcode:
Schau dir an, wie GetHashBytesFromFile programmiert ist.
var b : TByte;
rbs : rawbytestring; ... ... b := System.hash.THashMD5.GetHashBytesFromFile( ); oder rbs := System.hash.THashMD5.GetHashStringFromFile( ); ...BytesFromFile liefert dir den 128Bit Hash in 16Bytes, und die ...StringFromFile liefert dir einen hex-String der Länge 32. [Fritz hat mal eine Version gepostet, welche praktisch 1:1 gleich funktioniert. Die Version Fritz hasht aber bei der letzten Tranche über zu viele Bytes und liefert in fast nur in 1/1MB aller Fälle einen korrekten Wert.] Wenn du nur über Teile eines Files hashen willst, dann könntest du es wie im Code unten tun (ich habe hier die Bytevariante ausgebaut, die hex Variante kannst du daraus ja leicht gewinnen):
Delphi-Quellcode:
procedure AddHashBytes( var lHasher: THashMD5; const AStream: TStream; von, bis : int64 );
const BufferSize = 64*1024; var lStreamBytes: TBytes; Lies, SollLesen : int64; len : integer; begin if bis >= AStream.size then bis := Astream.size-1; if von < 0 then von := 0; if bis >= von then begin setlength(lStreamBytes, BufferSize); AStream.Position := von; SollLesen := bis-von+1; while SollLesen > 0 do begin if SollLesen >= BufferSize then Lies := BufferSize else Lies := SollLesen; len := Astream.ReadData(lStreamBytes, Lies); if len = 0 then break; dec(SollLesen,len); lHasher.Update(lStreamBytes, len); end; end; end; function GetHashFromFile( aFileName : string; vonbis : array of int64 ) : TBytes; var f : TFileStream; LMD5: THashMD5; i, len : integer; von, bis : int64; begin f := TFileStream.Create( aFileName, fmOpenRead ); try LMD5 := THashMD5.Create; LMD5.Reset; len := length(vonbis); if len < 2 then begin AddHashBytes( LMD5, f, 0, f.Size-1 ); end else begin i := 0; while len-i >= 2 do begin von := vonbis[i]; bis := vonbis[i+1]; if von < 0 then von := f.Size+von; if bis < 0 then bis := f.Size+bis; AddHashBytes( LMD5, f, von, bis); inc(i,2); end; end; Result := LMD5.HashAsBytes; finally f.Free; end; end; Mögliche Aufrufe: Beispiel 1: Wenn du von Byte 0 bis 2000 und von Byte 2001 bis ans Ende hashen willst: GetHashFromFile( filename, [0, 2000, 2001, maxint] ); Damit hashst du ja übers ganze File und erhältst natürlich exakt den gleichen Wert wie via System.hash.THashMD5.GetHashBytesFromFile( filename ); Beispiel 2: Wenn du Bytes 192435 - 192450 nicht "mithashen" willst: GetHashFromFile( filename, [0, 192434, 192451, maxint] ); Beispiel 3: Negative Werte: Wenn du die letzten 16 Bytes des Files nicht hashen willst: GetHashFromFile( filename, [0, -17] ); Ich hoffe, das hilft. Korrekturen bitte direkt an mich - Dankeschön. |
AW: DEC 5.2 String hashen?
Zitat:
du kannst natürlich eine String-Struktur als Aufbewahrungsort Deiner Bytes verwenden aber das schein mir hier so sinnvoll wie sich ein Loch in die Kniescheibe zu bohren und Marmelade hinein zu schmieren, machen kann man viel wenn der Tag lang ist. Zitat:
Gruß K-H |
AW: DEC 5.2 String hashen?
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
Den Dateiinhalt mit am Ende hängenden Hash, lese ich so aus
aByteStream := TBytesStream.Create;
try aByteStream.LoadFromFile(aFileName); aByteStream2 := TBytesStream.Create; try aByteStream2.Write(aByteStream.Bytes[0], aByteStream.Size); // aktuellen Stream zwischenspeichern sHash := THashFunctions_Selftest.CalcHash(Trim(TEncoding.ANSI.GetString(aByteStream2.Bytes))); // einen Hash der im neu erzeugten Stream enthaltenen Bytes erzeugen aByteStream.Size := aByteStream.Size + iHashLengthInBytes; // die Größe des ALTEN streams um maximale Länge des Hashs vergrößern (?) Move(AnsiString(sHash)[1], aByteStream.Bytes[aByteStream.Size - iHashLengthInBytes], iHashLengthInBytes); // Hash im alten Stream ablegen aByteStream.SaveToFile(aFileName); // Alten, modifizierten Stream speichern finally aByteStream2.Free; end; finally aByteStream.FreeM end; // Eine kürzere Variante, ohne aByteStream2 wäre sHash := THashFunctions_Selftest.CalcHash(Trim(TEncoding.ANSI.GetString(aByteStream.Bytes))); // einen Hash der im Stream enthaltenen Bytes erzeugen aByteStream.Size := aByteStream.Size + iHashLengthInBytes; // die Größe des ALTEN streams um maximale Länge des Hashs vergrößern (?) Move(AnsiString(sHash)[1], aByteStream.Bytes[aByteStream.Size - iHashLengthInBytes], iHashLengthInBytes); // Hash im alten Stream ablegen aByteStream.SaveToFile(aFileName); // Stream speichern
Delphi-Quellcode:
if aByteStream.Size > iHashLengthInBytes then
begin aByteStream.Read(aByteStream.Bytes[0], aByteStream.Size - iHashLengthInBytes); Result := THashFunctions_Selftest.CalcHash(Trim(TEncoding.ANSI.GetString(aByteStream.Bytes, 0, aByteStream.Size - iHashLengthInBytes))); end; // Dateiinhalt könnte sein: _TEST_TEST_2B3CC5E89E09A889CC10D0021284AB06EA6FF72BCFE78110C8D9B71A6030375F // Ausgelesen wird dann "_TEST_TEST_" und davon er Hash gebildet. |
AW: DEC 5.2 String hashen?
Zitat:
Das liegt nicht an Delphi - du vergleichst hier zwei Hash Funktionen miteinander. Ich habe dir anhand eines Beispiels [md5] zeigen wollen, wie du bei der Berechnung des MD5 Hashs einer beliebig grossen Datei immer nur einen Teil und nie das ganze File laden musst. [Du hattest wegen RAM schiesst in die Höhe geschrieben - und ich dachte ich mache dir eine Freude, wenn du siehst, dass dies nicht sein muss. ;-) und erst noch alles in Byte statt string] Wenn du lieber SHA1 verwendest, dann verwendest du lieber SHA1 - dein Entscheid... sei mit deinem Code erst dann zufrieden, wenn eine Suche nach dem Wort "string" ins Leere läuft. Wenn du alles in deinem Code Byte basiert machst, passieren auch nicht Fehler wie dieser hier: Weg mit dem Trim [ich weiss, ich wiederhole mich] Grund: Solltest du mit diesem Code irgendwann den Hash Wert einer Datei mit Leerzeichen am Anfang oder Ende des Files berechnen wollen [OK, wie erwähnt bei .exe mind. am Anfang nicht der Fall], dann rechnest du diese nicht mit und die Berechnung geht in die Hose.
Delphi-Quellcode:
sHash := THashFunctions_Selftest.CalcHash([B]Trim([/B]TEncoding.ANSI.GetString(aByteStream.Bytes)));
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:59 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