Objekt binär speichern
-
Hallo!
Ich möchte bestimmte Members einer Klasse in eine Binärdatei speichern. Als Beispiel nehmen wir mal die Klasse Mitarbeiter:
class Mitarbeiter { private: string name; string adresse; int alter; float gehalt; // ... }
Da ich meistens mit C# arbeite, ist der Standardweg zum Speichern einer Collection von solchen Mitarbeitern natürlich XML, mit dem Ergebnis:
<!-- weitere Daten --> <MitarbeiterSammlung> <Mitarbeiter> <Name>Donald Duck</Name> <Adresse>Entenhausen</Adresse> <Alter>36</Alter> <Gehalt>3000</Gehalt> </Mitarbeiter> <Mitarbeiter> <Name>Goofy</Name> <Adresse>Entenhausen</Adresse> <Alter>35</Alter> <Gehalt>3100</Gehalt> </Mitarbeiter> <!-- usw. --> </MitarbeiterSammlung> <!-- weitere Daten -->
Meine Frage ist nun, wie würde ich das mit C++ binär speichern?
Danke schon mal im Voraus!
-
die pod-typen (float/int/char etc) kannst du einfach binär in eine datei schreiben, bei strings wirds wegen der variablen länge schwieriger. du kannst aber z.b. einfach die ganze datei einlesen in einen buffer, dann z.b. konkret byte 0-4 als int, byte 5 bis nächster '\0' string etc
-
Also erst mal danke für die schnelle Hilfe. Ich möchte aber noch eine Frage anhängen. Gibt's auch eine Möglichkeit gleich eine Ganze Klasse (z.B. Mitarbeiter) in eine Datei zu schreiben bzw. von einer Datei zu lesen, oder muss ich die Klasse Stück für Stück aus den pod-Typen und Strings zusammensetzen?
-
soweit ich weis musst du selbst hand anlegen. wenn die klasse allerdings nur aus pods besteht, dann gehts einfacher:
struct eintrag { int wert1; char wert2; float wert3; }; eintrag myentry; ofstream.write(&myentry, sizeof(eintrag)); ofstream.read(&myentry, sizeof(eintrag));
hab das jetz nicht gecheckt, hab das aber so in erinnerung
-
tommazzo schrieb:
Gibt's auch eine Möglichkeit gleich eine Ganze Klasse (z.B. Mitarbeiter) in eine Datei zu schreiben bzw. von einer Datei zu lesen,
die gibts. write(foo,sizeof(foo))...
aber das fliegt dir eh nur um die ohren. bei strings zuerst mal, weil du da nur den zeiger auf die nutzdaten wegspeicherst aber die nurtzdaten nicht. nach dem laden haste dann nur nen zeiger ins nirwana. dann bei virtuellen funktionen, denn du speicherst den vptr mit und der zeigt nach dem nächsten compilieren ins nirvana.oder muss ich die Klasse Stück für Stück aus den pod-Typen und Strings zusammensetzen?
jo. mach das. hast in c++ keine performance-nachteile, wenn du so vorgehst.
zum üben sollte es erstmal ascii-text sein statt gleich binär. am schnellsten (und saubersten wegen default-ctors, die nicht sein dürfen) iststruct eintrag { int wert1; char wert2; float wert3; eintrag(ifstream& in){ in>>wert1; in>>wert2; in>>wert3; } void save(ofstream& out){ out<<wert1<<'\n'; out<<wert2<<'\n'; out<<wert3<<'\n'; } };
wenn in einer liste nur basisklassnezeiger stehen, dann muß auch noch der klassenname als erste zeile rein in jeden datensatz, dann kann die einleseschleife mit if/else auch genau den richtigen ctor aufrufen.
evtl isses angebracht, den istream auf exceptionwerfend umzustellen.
wenn das klappt, kannste bestimmt gut auf binär-schreiben umstellen.
-
OK, vielen Dank! Genau das wollte ich wissen.
-
Die hier genannten Loesungen sind uebrigens nicht plattformunabhaengig.
Das ist auch der Grund, warum Microsoft bei C# XML-Dateien verwendet.
Man kann sich mit einigem Aufwand ein Serialisierungs-Framework schreiben, das Objekte z.B. plattformunabhaengig in echte Binaerdaten umwandelt oder auch in XML.
Serialisierung ist leider noch kein Standardfeature der C++ Library.
-
Power Off schrieb:
Die hier genannten Loesungen sind uebrigens nicht plattformunabhaengig.
wo ist meine plattformabhängig?
Das ist auch der Grund, warum Microsoft bei C# XML-Dateien verwendet.
nein. ms benutzt es, weil es ein schönes buzz-word ist.
Man kann sich mit einigem Aufwand ein Serialisierungs-Framework schreiben, das Objekte z.B. plattformunabhaengig in echte Binaerdaten umwandelt oder auch in XML.
aber nicht plattformunabhängig. und wozu?
Serialisierung ist leider noch kein Standardfeature der C++ Library.
zum glück.
-
volkard schrieb:
wo ist meine plattformabhängig?
Das Lesen und Schreiben von Zahlen in ASCII-Form unterliegt auch den Beschraenkungen der jeweiligen Datentypen.
Das Schreiben von "\n" fuehrt auf einem Windows-Rechner (bei Textdateien) dazu, dass "\r\n" geschrieben wird. Beim Einlesen auf einer UNIX-Maschine (wo es nur Binaerdateien gibt) fuehrt zu einem Fehler, weil "\r" im Eingabestrom ist.
volkard schrieb:
nein. ms benutzt es, weil es ein schönes buzz-word ist.
Nein, weil es einfacher zu handhaben ist. Man nehmem einen Texteditor und schon kann man die Daten aendern, ohne einen Spezialeditor fuer eine evtl. Binaerdatei schreiben zu muessen. Jedoch brauchen Binaerdateien weniger Platz. Ein MS-Entwickler sagte mal ueber SOAP: "Toll, jetzt wissen wir endlich, womit wir zukuenftige Terabyte-Festplatten zuballern koennen.
"
volkard schrieb:
Power Off schrieb:
Man kann sich mit einigem Aufwand ein Serialisierungs-Framework schreiben, das Objekte z.B. plattformunabhaengig in echte Binaerdaten umwandelt oder auch in XML.
aber nicht plattformunabhängig. und wozu?
Doch. Binaerdaten lassen sich plattformunabhaengig speichern:
void write_uint32( ubyte_t* buf, uint32_t src ) { buf[0] = (ubyte_t) ( src >> UINT32_C(24) ) & UBYTE_C(0XFF); buf[1] = (ubyte_t) ( src >> UINT32_C(16) ) & UBYTE_C(0XFF); buf[2] = (ubyte_t) ( src >> UINT32_C( 8) ) & UBYTE_C(0XFF); buf[3] = (ubyte_t) ( src ) & UBYTE_C(0XFF); }
(Uebrigens, "& UBYTE_C(0XFF)" schliesst auf Maschinen mit char's groesser als 8 Bit aus, dass die oberen Bits gesetzt sind)
volkard schrieb:
Power Off schrieb:
Serialisierung ist leider noch kein Standardfeature der C++ Library.
zum glück.
Leider.
Wuerde der Welt eine Menge *******-Code ersparen.
-
Da gibts doch was von Boost?!
-
Power Off schrieb:
Leider.
Wuerde der Welt eine Menge *******-Code ersparen.ja. deine parser!
-
volkard schrieb:
ja. deine parser!
Oh, Du hast ja noch gar keinen richtigen von mir gesehen ...
-
man kann sich aber schon sehr gut vorstellen wie die aussehen.
-
hellseher schrieb:
man kann sich aber schon sehr gut vorstellen wie die aussehen.
Na ja, Du weisst ja alles.
-
Wenns auf geschwindigkeit ankommt, und der Pladdenplatz nur 2. rangig ist, wuerd ich definitiv immer mit festen blockgreossen arbeiten ...
class Mitarbeiter { private: string name; string adresse; int alter; float gehalt; // ... }
wuerde erst mal zu
class Mitarbeiter { private: char name[MAXSTRINGLENGTH]; char adresse[MAXSTRINGLENGTH]; int alter; float gehalt; // ... }
werden ... das kannst dan schoen blockweisse lesen und schreiben und mit relativen positionen auf dem binaeren file rumrutschen ....
wenn auf die positionierung verzichtest, oder mit temp files arbeitest, oder ne position / compression selber implementierst ... kannst auch gleich das zippen "mitprogrammieren"
Wenn du instanzen unterschiedlicher klassen mit unterschiedlichen Groessen hasst solltes die Abhaengigkeiten datanbank-like in indizies auslagern, und beim ein auslesen die verbindungen aufbauen ...
meist liest schreibst dann in mehreren schritten, wo die objecte im speicher teilweise mehrmals gewandelt werden .... mit nem mehr oder weniger komplexen cache mechanismus (richtig kompliziert wirds, wenn deine datenstruktur selbst im "geparsten" zustand nimmer in den heap/freestore passt)
Ciao ...
-
RHBaum schrieb:
Wenn du instanzen unterschiedlicher klassen mit unterschiedlichen Groessen hasst solltes die Abhaengigkeiten datanbank-like in indizies auslagern, und beim ein auslesen die verbindungen aufbauen ...
Kannst du mir das mit der Datenbank bitte etwas genauer erklären? Wie würdest du eine aufbauen?