Autor |
Beitrag |
Metschu
      
Beiträge: 135
Windows XP SP2 Home
Delphi 7; Delphi XE2-Starter
|
Verfasst: So 16.05.10 14:34
Hallo zusammen!
Ich speichere Daten in einer TRecord Datei.
Wenn ich nun aufgrund eines Updates neue Variablen in TRecord aufnehme, werden mir ja logischerweise beim laden von alten Dateien die Variablen durcheinander gebracht.
Derzeit schreibe ich ein seperates Tool, um die Dateien umzuwandel und muß die dann alle einzeln auswählen.
Habe ich beim speichern die Möglichkeit, der Datei eine Versionsnummer zuzuordnen?
So kann man beim Laden die Version der Datei prüfen und wenn diese älter ist, automatisch innerhalb der Software anpassen ohne das seperate Tool.
Oder gibts auch ganz andere, einfachere Wege?
Danke schonmal.
Gruß
Torsten
|
|
jaenicke
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 16.05.10 15:54
Normalerweise gibt es dafür einen Dateikopf, in dem die Informationen zum Format usw. stehen.
Wenn du natürlich aus irgendwelchen Gründen einen file of TXyRecord hast, dann geht das nicht. Dann muss der Benutzer die Umwandlung anstoßen. Würde ich nicht so machen.
Ich habe immer die einfachste Lösung genommen. Eigenes Dateiformat, optimiert für schnelle Zugriffe, da ich zusätzliche Navigationsinfos einbinden kann. Entsprechende Klassen mit LoadFromFile und SaveToFile, schon funktioniert alles. Beim Laden wird an Hand der Versionsangabe ggf. intern eine Konvertierung des Streams durchgeführt, fertig.
Zusätzlich gibt es bei mir reservierte Nullfelder, die dann in späteren Versionen eine Erweiterung des Formats erlauben ohne dabei die Verarbeitbarkeit in alten Versionen zu verbauen (nur neue Informationen sind dort dann eben nicht sichtbar).
|
|
dummzeuch
      
Beiträge: 593
Erhaltene Danke: 5
Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
|
Verfasst: So 16.05.10 15:57
Metschu hat folgendes geschrieben : |
Ich speichere Daten in einer TRecord Datei.
Wenn ich nun aufgrund eines Updates neue Variablen in TRecord aufnehme, werden mir ja logischerweise beim laden von alten Dateien die Variablen durcheinander gebracht.
Derzeit schreibe ich ein seperates Tool, um die Dateien umzuwandel und muß die dann alle einzeln auswählen.
Habe ich beim speichern die Möglichkeit, der Datei eine Versionsnummer zuzuordnen?
So kann man beim Laden die Version der Datei prüfen und wenn diese älter ist, automatisch innerhalb der Software anpassen ohne das seperate Tool.
|
Genau deshalb verwendet man bei komplexeren Programmen Datenbanken bzw. Tabellen, da gibt es jeweils die Moeglichkeit, dass das Programm prueft, welche Felder mit welchem Datentyp es gibt.
Allerdings haben Datenbanken gegenueber Records mindestens zwei Nachteile:
1. Sie sind deutlich langsamer
2. Sie sind aufwaendiger zu programmieren
Julian Bucknall beschreibt in seinem Buch "Tomes of Delphi: Algorithms and Data Structures" eine TtdRecordFile Klasse, die die von Dir gewuenschten Optionen bietet. Das funktioniert so, dass er am Anfang jeder Datei eine bestimmte Anzahl Bytes reserviert, in der er Verwaltungsinformationen ablegt, u.a. die Groesse des in der Datei gespeicherten Records. Dann gibt es je eine Read und Write Methode, die anhand eines Index ein Seek auf die Datei macht und einen Record liest bzw. schreibt.
(Das Buch kann ich uebrigens sehr emfpehlen.)
Im Prinzip laeuft das so (ungetestet, compiliert vermutlich noch nicht mal):
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: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75:
| type TRecordFile = class private FHeaderSize: integer; FRecordSize: integer; FStream: TFileStream; public constructor Create(const _Filename: string; _HeaderSize: integer; _RecordSize: integer); destructor Destroy; override; procedure WriteHeader(var _Header); procedure ReadHeader(var _Header); procedure Write(_Idx: integer; var _Record); procedure Read(_Idx: integer; var _Record); end;
constructor TRecordFile.Create(const _Filename: string; _HeaderSize: integer; _RecordSize: integer); begin inherited Create; FHeaderSize := _HeaderSize; FRecordSize := _RecordSize; FStream := TFileStream.Create(Filename); end;
destructor TRecordFile.Destroy; begin FreeAndNil(FStream); inherited Destroy; end;
procedure TRecordFile.Write(_Idx: integer; var _Record); begin FStream.Seek(FHeaderSize + _Idx * FRecordSize); FStream.Write(_Record, FRecordSize); end;
procedure TRecordFile.Read(_Idx: integer; var _Record); begin FStream.Seek(FHeaderSize + _Idx * FRecordSize); FStream.Read(_Record, FRecordSize); end;
procedure TRecordFile.WriteHeader(var _Header); begin FStream.Seek(0); FStream.Write(_Header, FHeaderSize); end;
procedure TRecordFile.ReadHeader(var _Header); begin FStream.Seek(0); FStream.Read(_Header, FHeaderSize); end;
var st: TRecordFile; Header: record Version: integer; end; Rec: record end; begin st := TRecordFile.Create('c:\test.dat', SizeOf(Header), SizeOf(Rec)); try st.ReadHeader(Header); if Header.Version <> ErwarteteVersion then begin KonvertierenUndNeuOeffnen(st); end; st.Read(0, Rec); finally FreeAndNil(st); end; |
Ein Kollege (Hi DS) hat darauf basierend eine Dateistruktur entwickelt, die sich selbst beschreibt, also den darin gespeicherten Record mit seinen Feldern und diverse andere Angaben, so dass ein Programm die Daten lesen kann, ohne zu wissen, welche Records gespeichert sind. Aber sowas kompliziertes brauchst Du ja erstmal gar nicht, es reicht ja, wenn Du im Header eine Versionsinfo stehen hast.
twm
|
|
jaenicke
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 16.05.10 16:11
Wobei mir eine Notlösung für Records einfällt: Einfach in jedem Record als erstes einen Versionsstempel speichern. Bläht zwar die Datei etwas auf, dafür muss am bestehenden Code nicht viel geändert werden.
dummzeuch hat folgendes geschrieben : | Ein Kollege (Hi DS) hat darauf basierend eine Dateistruktur entwickelt, die sich selbst beschreibt, also den darin gespeicherten Record mit seinen Feldern und diverse andere Angaben, so dass ein Programm die Daten lesen kann, ohne zu wissen, welche Records gespeichert sind. |
Hört sich sehr nach XML an, zumindest habe ich das ziemlich genau so wie du es beschreibst damit umgesetzt.
|
|
Metschu 
      
Beiträge: 135
Windows XP SP2 Home
Delphi 7; Delphi XE2-Starter
|
Verfasst: So 16.05.10 19:46
jaenicke hat folgendes geschrieben : | Normalerweise gibt es dafür einen Dateikopf, in dem die Informationen zum Format usw. stehen.
Wenn du natürlich aus irgendwelchen Gründen einen file of TXyRecord hast, dann geht das nicht. Dann muss der Benutzer die Umwandlung anstoßen. Würde ich nicht so machen. |
Gibt es verschiedene Typen von TRecord?
Ich definiere diese so (Beispiel):
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| Type TVariable = record Variable1 : ShortString; Variable2 : Integer; Variable3 : Boolean; end; |
In der Procedure wird das dann so definiert:
Delphi-Quelltext 1: 2: 3:
| var V : TVariable; F1 : File of TVariable |
Kann man mit dieser variante den Dateikopf anpassen?
Wenn ja, wonach muß ich suchen?
Danke schonmal.
Gruß
Torsten
|
|
jaenicke
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 16.05.10 19:53
Nein, so geht es eben nicht. Deshalb sagte ich ja, dass ich es nicht so mache.
Ich speichere mehrere Daten in der Datei und als erstes eben den Dateikopf. Mit Records hat das nichts zu tun, ich nutze dafür wie gesagt Klassen.
Und eine weitere Variante mit Nutzung von Records wurde ja auch schon gezeigt. 
|
|
dummzeuch
      
Beiträge: 593
Erhaltene Danke: 5
Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
|
Verfasst: So 16.05.10 22:17
jaenicke hat folgendes geschrieben : |
dummzeuch hat folgendes geschrieben : | Ein Kollege (Hi DS) hat darauf basierend eine Dateistruktur entwickelt, die sich selbst beschreibt, also den darin gespeicherten Record mit seinen Feldern und diverse andere Angaben, so dass ein Programm die Daten lesen kann, ohne zu wissen, welche Records gespeichert sind. | Hört sich sehr nach XML an, zumindest habe ich das ziemlich genau so wie du es beschreibst damit umgesetzt. |
Im Prinzip aehnlich, aber binaer. Das selbstbeschreibende Format ist auch nur als Zusatzfeature gedacht, falls man mal nicht das passende Program zu Hand hat und mal mit einem generischen Betrachter "reinsehen" will. Ausserdem stehen noch ein paar zusaetzliche Angaben im Header, u.a. welches Program die Datei wann und wo erzeugt hat. Normalerweise wird die Datei trotzdem als File of Record mit einem Header variabler Laenge gelesen. Das ist einfach um Klassen schneller.
Wir haben da ein Fremdprogramm im Einsatz, das die Daten als XML erwartet. Da dreht man immer stundenlang Daeumchen, bis das ein paar hundert Datensaetze eingelesen hat....
twm
|
|
Hobby-Programmierer
      
Beiträge: 238
Erhaltene Danke: 4
Win XP Pro, Vista Ultimate Trial :o)
D6 Pro, D7 Pro, Turbo, XE SE
|
Verfasst: Mo 17.05.10 01:57
Moin ...,
ich hatte vor Jahren für eine Arbeitszeitdatenbank den Header mittels variable Records am Anfang der Datei geschrieben.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| TIndexRec = Record case Daten: TIdx_Data of Header: (HFlag : Boolean; HVer : String[5]; HBID : Cardinal; HCrypt: String[25]); Calender:(DTag: TDate; DVfy: Boolean; DFt : Byte; DInx: Byte; DBeg: TTime; DEnd: TTime;
L_Azv: Word); end; |
Würde jetzt zwar auch Klassen verwenden, aber als Denkanstoss kann mna das ja immer noch gebrauchen.
LG Mario
|
|
Reinhard Kern
      
Beiträge: 591
Erhaltene Danke: 14
|
Verfasst: Mo 17.05.10 14:48
Hobby-Programmierer hat folgendes geschrieben : | ...Würde jetzt zwar auch Klassen verwenden, aber als Denkanstoss kann mna das ja immer noch gebrauchen.
LG Mario |
Hallo,
das eine (Klassen) hat doch mit dem anderen (file of TxxRecord) garnichts zu tun. Zweckmässig wäre es natürlich eine Klasse anzulegen, bei der nach aussen garnicht sichtbar ist, ob sie file of verwendet oder Tabellen oder SQL oder sonstwas.
Gruss Reinhard
|
|
|