Das eigene Objekt speichern
-
Hallo!
In meinem Programm will ich eine Methode save() und load() einbauen. Mit diesen Methoden soll sich das Obejkt selber seine Attribute in Dateien speichern und aus Dateien laden.
Die Attribute des Objektes sind unsigned int, bool oder string.Wenn ich also das Objekt habe( vereinfachtes Beispiel ):
class Daten { public: unsigned int foo; bool bar; string baz; bool load( ) { ifstream file( "test.dat", ios::binary|ios::in ); if( !file.is_open() ) { return false; } file.read( this, sizeof( this ) ); // <-- FEHLER! file.close(); return true; } bool save( ) { ofstream file( "test.dat", ios::binary|ios::out ); if( !file.is_open() ) { return false; } file.write( this, sizeof( this ) ); // <-- FEHLER! file.close(); return true; } };
Dann meckert der Kompiler in den Zeilen, so sizeof steht( Zeilen sind durch Kommentare vermerkt ).
Hier sind die Fehlermeldungen des Kompilers, die ich nicht so recht deuten kann:`In member function ‘virtual bool Daten::load()’:
error: no matching function for call to ‘std::basic_ifstream<char, std::char_traits<char> >::read(Daten* const, unsigned int)’
note: candidates are: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::read(_CharT*, std::streamsize) [with _CharT = char, _Traits = std::char_traits<char>]
In member function ‘virtual bool Daten::save()’:
error: no matching function for call to ‘std::basic_ofstream<char, std::char_traits<char> >::write(Daten* const, unsigned int)’
note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::write(const _CharT*, std::streamsize) [with _CharT = char, _Traits = std::char_traits<char>]
=== Build finished: 2 errors, 0 warnings ===`
Ich nutze Code::Blocks( GNU GCC Kompiler ) unter Linux 9.10
Kann mir da jemand helfen?MfG. Ich
-
Die Klasse byteweise zu lesen und zu schreiben ist eine ganz schlechte Idee, da sie kein POD ist.
std::string
wird auf diese Weise mit Sicherheit falsch serialisiert. Wieso speicherst du nicht im Textformat?(Der Fehler bestünde bei dir darin, dass
char*
erwartet wird).
-
Wieso speicherst du nicht im Textformat?
Weil das mir zu aufwändig schien.
Ich kann ja da nict einfach nur reinschreiben. Da muss ich wieder mit Trennzeichen etc arbeiten und beim Lesen darauf achten. Da erschien mit das mit dem file.read/write schneller, weswegen ich es dann verwendet hatte.Wenn ich das mit den Texten mache, müsste ich dann sowas machen, denke ich:
class [...] unsigned int foo; bool bar; string baz;
Und das wird dann zu:
`5|
0|
Hallo Welt
Zeilenumbruch
und weiter gehts`
Wie würdest du das machen?
Im RL sind das für die Datei10 String-Variablen
4 Boolean-Variablen und
3 unsigned int-VariablenDabei können die Strings Zeilenumbrüche haben, weswegen ich auch nicht 1-Variable-1-Zeile umsetzen kann...
MfG. Ich
-
Ich würde boost::spirit oder etwas Selbstgemachtes empfehlen. Man liest die Datei (binär) komplett ein und parst sie dann.
Sowas in der Art:
void skipSpaces(const char **pos, const char * const end) { while (isspace(...)) ... } bool parseInt(int &out_value, const char **pos, const char * const end) { skipSpaces(); char buf[256]; while (isdigit(...)) buf[..] = ...; out_value = atoi(buf); return true; }
-
ChristophLu schrieb:
Wieso speicherst du nicht im Textformat?
Weil das mir zu aufwändig schien.
Ich kann ja da nict einfach nur reinschreiben. Da muss ich wieder mit Trennzeichen etc arbeiten und beim Lesen darauf achten. Da erschien mit das mit dem file.read/write schneller, weswegen ich es dann verwendet hatte.In Text reinschreiben und rauslesen ist sicher nicht schwieriger als es binär zu machen. Man verschiebt lediglich die Probleme, die man ohnehin hat, woanders hin.
Natürlich ist es nicht trivial einen 'beliebigen' String abzuspeichern und korrekt wieder einzulesen, aber mal angenommen es stehen zumindest druckbare Zeichen drin (inklusive LF, TAB und Leerzeichen), dann lässt sich dass schon mit relativ wenig Aufwand sicher bewerkstelligen.#include <string> #include <iostream> #include <fstream> class Daten // Daten ist mit der unpassendes Name für eine Klasse { public: Daten() // der Konstruktor sorgt dafür, dass alle Member gleich sinnvolle Werte annehmen : foo( 42 ), bar( false ), baz( "Das sind zwei Zeilen\n2. Zeile\n" ) {} unsigned int foo; // public Member! bool bar; std::string baz; // -- Save friend std::ostream& operator<<( std::ostream& out, const Daten& d ) { return out << d.foo << " " << d.bar << "|" << d.baz << "|\n"; } // -- Load friend std::istream& operator>>( std::istream& in, Daten& d ) { char delimiter; return getline( in >> d.foo >> d.bar >> delimiter, d.baz, '|' ); } }; int main() { using namespace std; { Daten d; d.foo = 77; // d speichern ofstream file( "test.dat" ); file << d; } { // d2 laden Daten d2; ifstream file( "test.dat" ); if( file.is_open() ) { file >> d2; cout << "Gelesen: " << d2 << endl; } else cerr << "Fehler beim Oeffnen der Datei" << endl; } return 0; }
Der große Vorteil besteht darin, dass man die Datei mit einem einfachen ASCII-Editor überprüfen kann.
:xmas2: Werner
-
OT @Werner:
Warum machst du die Kommentare immer mit 2 Bindestrichen?
Erinnert mich irgendwie immer an Eiffel, wo die Kommentare so angefangen werden.
-
Werner Salomon schrieb:
Natürlich ist es nicht trivial einen 'beliebigen' String abzuspeichern und korrekt wieder einzulesen,...
Eigentlich schon, man muss nur die Größe vorher speichern.
-
drakon schrieb:
OT @Werner:
Warum machst du die Kommentare immer mit 2 Bindestrichen?was hier alles gefragt wird ...
ist 'ne Angewohnheit - 2 Bindestriche heisst soviel wie: der Kommentar bezieht sich auf das, was in den nächsten Zeilen kommt. Mache ich aber nicht konsequent.:xmas1: Werner
-
dahucoder schrieb:
Werner Salomon schrieb:
Natürlich ist es nicht trivial einen 'beliebigen' String abzuspeichern und korrekt wieder einzulesen,...
Eigentlich schon, man muss nur die Größe vorher speichern.
Ja natürlich, wenn man anschließend nur den String binär abspeichert. Aber das ist für den Einsatz in der Praxis nicht immer zu empfehlen. So eine Datei kann mal als Email verschickt werden oder auch von einem (ASCII-)Editor bearbeitet werden. Dann ist nicht mehr sichergestellt, dass dann die gesammelte binäre Information erhalten bleibt.
Wirklich lesbarer Text hat da einfach Vorteile - folglich sollte man beim Abspeichern auch darauf achten, dass kein Steuer/Sonder-Zeichen dort enthalten sind.
Gruß
Werner
-
Werner Salomon schrieb:
drakon schrieb:
OT @Werner:
Warum machst du die Kommentare immer mit 2 Bindestrichen?was hier alles gefragt wird ...
ist 'ne Angewohnheit - 2 Bindestriche heisst soviel wie: der Kommentar bezieht sich auf das, was in den nächsten Zeilen kommt. Mache ich aber nicht konsequent.:xmas1: Werner
Ich habe zuerst gedacht, dass du das irgendwie machst, damit du dann das ganze für einen Dokumentationsgenerator lesbar wird.
Aber naja: [/OT]
-
Werner Salomon schrieb:
dahucoder schrieb:
Werner Salomon schrieb:
Natürlich ist es nicht trivial einen 'beliebigen' String abzuspeichern und korrekt wieder einzulesen,...
Eigentlich schon, man muss nur die Größe vorher speichern.
Ja natürlich, wenn man anschließend nur den String binär abspeichert. Aber das ist für den Einsatz in der Praxis nicht immer zu empfehlen. So eine Datei kann mal als Email verschickt werden oder auch von einem (ASCII-)Editor bearbeitet werden. Dann ist nicht mehr sichergestellt, dass dann die gesammelte binäre Information erhalten bleibt.
Wirklich lesbarer Text hat da einfach Vorteile - folglich sollte man beim Abspeichern auch darauf achten, dass kein Steuer/Sonder-Zeichen dort enthalten sind.
Bei lesbarem Text hast du immer das Problem, dass der Separator escaped werden muss. Außerdem glaub ich auch nicht, dass er seine Klasse als Mail verschicken will.
-
Hallo,
ich hab das jetzt umgebaut:
Zuerst den gesamten Inhalt der Datei auslesen. Danach nach Trennzeichen( ich hab '|' genommen ) trennen( hab mir ne split-funktion geschrieben ) und die getrennten Teile in einen Vektor speichern. Danach kann ich relativ bequem mit dem Vektor arbeiten.Danke für die Tipps!
MfG. Ich