Autor |
Beitrag |
hRb
Beiträge: 269
Erhaltene Danke: 12
|
Verfasst: Do 26.03.20 18:15
Hallo zusammen,
die Frage zum "Optimalen" Lesen beliebiger Dateien blieb 12 Tage ohne Antwort. Ich zergliedere meine Frage neu, weil ich beim Realisieren meiner Aufgabe auf zwei Syntax-Probleme gestoßen bin, bei der ich Hilfe benötige. Aufgabe lautet nach wie vor: Einlesen einer beliebigen Datei ins Memory und Daten in Hexaform darstellen. Lade hierzu die Datei in einen MemoryStream. Habe dazu folgende Funktion geschrieben, die mich jedoch in mehreren Punkten nicht befriedigt:
1. Kann FiStream nicht mit der Option fmOpenRead or fmShareDenyNone einlesen. Dies führt bei schon geöffneter Datei zu error.
2. MemoryStream ist ein Pointer. Ich dachte hiermit auf die Daten direkt zugreifen zu können. Habe Syntax-Problem mit Pointer! (Über die Read-Funktion mit einem weiteren Buffer funktioniert mein Programm. (wäre aber ein weiteres Umspeichern der Daten). Wie greife ich auf die Daten von MemoryStrem direkt zu?
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| Function ReadFi(FileName:string):boolean; var Buffer: TBytes; FiStream : TMemoryStream; j: int64; s: string; begin try s:=''; FiStream := TMemoryStream.Create; FiStream.LoadFromFile(FileName); FiStream.Position := 0; SetLength(Buffer, FiStream.Size); FiStream.ReadBuffer(Pointer(Buffer)^, FiStream.Size); for j:=0 to 50 do s:= s + IntToHex(ord(Buffer[j]),2) + ' '; Form1.RichEdit1.Lines.Add(s); except on Exception do begin FiStream.Free; Result:=False; exit; end; end; FiStream.Free; Result:=true; end; |
|
|
Th69
Beiträge: 4777
Erhaltene Danke: 1054
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Do 26.03.20 19:08
Warum benutzt du hier überhaupt einen TMemoryStream und nicht gleich einen TFileStream?
|
|
Gausi
Beiträge: 8538
Erhaltene Danke: 475
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Do 26.03.20 19:46
Grade bei sehr, sehr großen Daten wird der Ansatz mit MemoryStream nicht mehr funktionieren, denke ich. Soweit ich weiß, lädt LoadFromFile die gesamte Datei in den Speicher - und bei 32-Bit-Anwendungen ist dann in der Regel irgendwo zwischen 1 und 2GB Schluss.
Daher: Mit FilesStream arbeiten, die Daten häppchenweise in den Buffer laden, verarbeiten, und dann den nächsten Teil laden.
Aber zu deiner Frage direkt: Das sollte so gehen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| var ms: TMemoryStream; p: ^Byte; b: Byte; i: Integer; p := ms.Memory; for i := 0 to 100 do begin b := p^; Memo1.Lines.Add(IntToStr(b)); inc(p); end; |
_________________ We are, we were and will not be.
|
|
hRb
Beiträge: 269
Erhaltene Danke: 12
|
Verfasst: Do 26.03.20 21:44
Zunächst Danke,
damit der Hintergrund meiner Frage besser erkennbar wird: Ich habe eine ganze Reihe von Speichersticks und Festplatten mit Sicherungskopien von Dateien, genauer gesagt auch ganze Ordner. Hier gibt es Textdateien aber auch andere Typen. Diese möchte ich auf Byteebene zu vergleichen. Einmal komplette Ordner, aber auch gezielt zwei Einzeldateien. Ein Vergleichsprogramm das auf Filename, Datum und Dateilänge vergleicht habe ich schon. Eigenartigerweise finde ich jedoch auch namensgleiche Dateien, die genau eine Stunde Differenzzeit aufweisen. Nun wollte ich mir ein eigenes Vergleichsprogramm schaffen. Gedacht war schon, dass ich immer Teilblöcke von 4096 Byte vergleiche und die Anzeige erst beim beim ersten Unterschied aktiviere.
Ich habe ein solches Programm mit Delphi 7 schon (mit einer schrecklichen Oberfläche). Ist auch viel zu langsam und knallt bei großen Dateien (war eines meiner Erstlingswerke, ohne try).
Werde nun, Eurem Rat folgend, mir TFilestream einmal genauer ansehen, wie dies gehen könnte. Oder kennt jemand einen Link auf ein Beispiel bei dem man spicken kann? Die Embarcadero-Hilfe zeigt zwar die Methoden, aber mir fehlen als Ungeübter die Beispiele.
Gruß hRb
|
|
Narses
Beiträge: 10182
Erhaltene Danke: 1255
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Fr 27.03.20 01:27
Moin!
hRb hat folgendes geschrieben : | Eigenartigerweise finde ich jedoch auch namensgleiche Dateien, die genau eine Stunde Differenzzeit aufweisen. |
So eigenartig ist das gar nicht. Das tritt auf oder kann auftreten, wenn man Sommerzeitunterschiede in zwei verschiedenen Dateisystemen (typisch: NTFS und FAT) hat. Die Differenz ist nur virtuell und auf die Art der Datumsspeicherung in den Dateisystemen zurückzuführen.
hRb hat folgendes geschrieben : | Nun wollte ich mir ein eigenes Vergleichsprogramm schaffen. |
Deinen Schaffensdrang in allen Ehren: wenn du einfach nur das Problem lösen willst (welches ausser dir noch ca. 3 Millionen Computernutzer weltweit sicher auch schon hatten ), dann nimm doch einfach eines der bereits existierenden Tools, wie den FreeFileSync. Das funktioniert bereits (und auch noch schnell), so dass du die Zeit in die Lösung des eigentlichen Problems investieren könntest.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Th69
Beiträge: 4777
Erhaltene Danke: 1054
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Fr 27.03.20 08:46
hRb hat folgendes geschrieben : | Eigenartigerweise finde ich jedoch auch namensgleiche Dateien, die genau eine Stunde Differenzzeit aufweisen. Nun wollte ich mir ein eigenes Vergleichsprogramm schaffen. |
Kennst du schon FreeFileSync (welches auch Zeitdifferenzen, welche meistens aufgrund von Sommer-/Winterzeit entstehen, beachtet)?
Edit: Ups, jetzt erst den letzten Beitrag von Narses gelesen ("2 Dumme, 1 Gedanke" - soll aber KEINE Beleidigung sein ;- ).
|
|
hRb
Beiträge: 269
Erhaltene Danke: 12
|
Verfasst: Fr 03.04.20 23:30
Hallo,
sorry, habe zu viel um die Ohren. So dauern Rückantworten bei mir immer etwas länger. Versuche auf die verschiedenen Fragen zu antworten.
1. Zitat: | Kennst du schon FreeFileSync ...? |
Nein, kannte ich bisher nicht. Habe es mal installiert. Sieht optisch gut ist und ist vermutlich auch ein sehr gutes leistungsfähiges Programm. Lande aber trotz Sprach-Einstellung "german" bei Hilfefragen immer im Internet auf einer englischen Hilfe-Seite.
2. Zitat: | Deinen Schaffensdrang in allen Ehren: ... nimm doch einfach eines der bereits existierenden Tools. |
Gedachtes Programm ist nicht für mich, sondern für meinen Bruder, der mit einem Rechner ganz bewusst keine Verbindung zum Internet herstellt / herstellen will. D.h. alle Programmme die zwangsweise (hier die Hilfe-Datei) aufs Internet zugreifen sind ungeeignet. Hilfe sollte zudem deutsch sein. Vielleicht weiß ja jemand ob und wo diese zu finden ist.
3. Habe Empfehlung aufgegriffen und meinen Quellcode mal von TMemoryStream auf TFileStream umgestellt und die Daten in einen Puffer eingelesen. Der Hinweis große Dateien scheibchenweise zu lesen ist ein überzeugendes Argument. Zur Hexa-Anzeige ist diese Methode auch ok. Allerdings: wenn ich eine Textdatei erkenne, mit welchem Aufruf lese ich dann die Zeilen ein?
Richedit1.Lines.LoadFromFile(Dateiname, vEncoding) ist halt eine bequeme Funktion und erledigt alles. Wenn man mir also die Verwendung von TFilestream empfiehlt, hat jemand ein fertiges Quellcodeschnippsel wie die Daten aus dem Puffer nach Richedit kommen? Möchte eigentlich nicht gerne Streams byteweise untersuchen und in Zeilen umwandeln. Da gibt es doch sicher etwas fertiges.
Danke wieder für Eure Geduld.
hRb
Moderiert von Th69: Delphi-Tags hinzugefügt
|
|
Th69
Beiträge: 4777
Erhaltene Danke: 1054
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Sa 04.04.20 08:54
Neben der LoadFromFile bietet die Klasse TStrings auch LoadFromStream - du solltest mehr Doku lesen.
|
|
hRb
Beiträge: 269
Erhaltene Danke: 12
|
Verfasst: Di 14.04.20 22:12
Hallo th69,
Zitat: | ...du solltest mehr Doku lesen. |
Hast im Grunde vollkommen recht. Lese allerdings in der Hilfe tatsächlich viel nach. Werde dort leider nicht immer fündig. Was den weniger Geübten häufig fehlt, sind Codeschnipsel (Beispiele). Die sind leider in diesem Forum nicht üppig.
Bin übrigens mit meinem Problem ein deutliches Stück weiter gekommen. Mal sehen, wann ich etwas "fertiges" vorstellen kann.
Habe leider an anderer Stelle neue Probleme. Danke zunächst für vorstehende Antworten.
hRb
|
|
jaenicke
Beiträge: 19284
Erhaltene Danke: 1742
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 15.04.20 07:43
Für das Laden großer Dateien bieten sich MMFs an. Dafür habe ich damals einmal eine Unit vorgestellt:
entwickler-ecke.de/viewtopic.php?p=607865
Es gibt darauf basierend auch eine Stream-Klasse von Flamefire für den schnellen Zugriff:
entwickler-ecke.de/viewtopic.php?t=100088
Für den Dateivergleich würde es aber schon reichen jeweils eine MMF mit der Klasse im ersten Link aufzumachen und einfach nach und nach durchzugehen und die Teile zu vergleichen. Dafür sind MMFs sehr gut geeignet. Denn es wird jeweils ein Bereich der Datei in den Arbeitsspeicher gemappt, so dass nicht bei jedem Lesezugriff auf die Dateien zugegriffen werden muss. Ansonsten bremst das auf normalen Festplatten den Vergleich unnötig aus, da man zwei Dateien an verschiedenen Positionen abwechselnd lesen muss.
|
|
hRb
Beiträge: 269
Erhaltene Danke: 12
|
Verfasst: Mi 15.04.20 22:15
Hallo Jaenicke,
das ist nochmals ein super guter Hinweis. Habe zwar im Forum und im Internet gesucht, diesen Beitrag bisher jedoch nicht gefunden. Habe jetzt genug zum "Kauen".
PS: einige Links auf forum.delphi-treff... lassen sich leider nicht mehr öffnen, evtl verschoben. Scheint aber nur eine zweite weitere Zugriffsquelle zu sein
Vielen Dank hRb
|
|