Mehrere Instanzen einer Klasse abspeichern



  • Mich nervt bei XML besonders der Overhead. Das bläht eine ansonsten recht kleine Datei doch sehr auf.


  • Mod

    Braunstein schrieb:

    Mich nervt bei XML besonders der Overhead. Das bläht eine ansonsten recht kleine Datei doch sehr auf.

    Man muss ja auch nicht zwangsläufig gleich zu XML greifen. Bei sehr vielen Anwendungen reichen Formate wie "Alle Zahlen nacheinander", "Ein String pro Zeile" oder auch das gute alte CSV. Hier im Thread ist das Problem, dass uns fast überhaupt gar nichts über die Daten und die Anwendung bekannt ist, das läuft dann bei den Antworten eben auf allerallgemeinste Formate hinaus.



  • sulky schrieb:

    aber in der ausgabefunktion folgt eine Fehlermeldung auf

    is>>e.a>>e.s;>>e.next;
    

    wieso das?

    Wie soll dir jemand die Frage beantworten, wenn du noch nicht einmal die Fehlermeldung nennst und wann du sie bekommst?
    Im Zweifelsfall hast du die Zeile tatsächlich so geschrieben und ein ; zuviel.



  • Sorry aber deine Lösung ist für mich ein Hack.

    Blödsinn, das ist die Standardlösung für Array-Serialisierungen.

    Wer garantiert dass das Format sauber dokumentiert wird, s.d. in 5 Jahren, wenn jemand den Code wieder anfasst, das Datenformat auch ohne Probleme versteht.

    Wovon redest du?

    Was spricht dagegen in solchen Fällen die Klassendefinitionen ins XML Format zu wandeln. Ist lesbarer als deine Lösung und eindeutiger definiert.

    Lol, das ist jetzt nicht dein ernst, oder? 👎 😮



  • Hallo zusammen, vielen Dank für eure Hilfe.
    Auch wenn ich nicht alles bis ins detail verstehen konnte.

    Hier nochmals meine Klasse. Neu will ich (auf Rat aus diesem Forum) den Zeiger auf die nächste Instanz nicht mehr mit abspeichern, da nach einem Computerneustart die Instanz wohl kaum mehr an der gleichen Stelle befinden
    wird.

    class element
    {
    public:
    int a;
    string s;
    element*next;
    
    friend ostream& operator<<(std::ostream& os, element const& e)
        {
            os<<e.a<<e.s;
    
    		// Die ganzen Member von e in os reinschreiben
             return os; // Referenz auf Stream zurückgeben -> damit os << a << b << c möglich wird
        }
    
    friend istream& operator>>(std::istream& is, element& e)
        {
             is>>e.a>>e.s;
             return is; // ~ zurückgeben -> damit is >> a >> b >> c möglich wird.
        }
    };
    

    und hier das Testprogram, welches auch funktioniert:

    int _tmain(int argc, _TCHAR* argv[])
    {
    element m;
    m.a=7;
    m.s="hallo";
    
    std::ofstream os("Bla.txt");
    os << m; 
    os.close();
    
    std::ifstream stream("Bla.txt");
    element k;
    stream >> k;
    
    cout<<k.a<<"   "<<k.s<<endl;
    }
    

    Nun möchte ich ja aber nicht eine Instanz abspeichern, sondern mehrere:
    Dazu erweitere ich mein Testprogram wie folgt:

    int _tmain(int argc, _TCHAR* argv[])
    {
    element m;
    m.a=7;
    m.s="hallo";
    
    element n;
    n.a=5;
    n.s.hello;
    
    std::ofstream os("Bla.txt");
    os << m; 
    
    //hier stehe ich an. Jetzt möchte ich n doch auch noch in die selbe    
    //datei speichern
    
    os.close();
    
    std::ifstream stream("Bla.txt");
    element k;
    element l; //nun brauche ich ein zweites Element, welches n ersetzt 
    stream >> k;
    
    stream >> l; //ob dies so richtig ist, bin ich mir überhaut nicht sicher.
    
    cout<<k.a<<"   "<<k.s<<endl;
    
    cout<<l.a<<"   "<<l.s<<endl; //und auch hier der Test, ob l und n identisch sind
    }
    

    nun sind folgende Probleme noch ungelöst:

    1. Wie schreibe ich ein zweites Element in dieselbe datei?
    2. Funkioniert das lesen des zeiten Elementes auf diese Weise?
    3. (Bereits in diesem Forumsbeitrag erwähnt) Wie passe ich den String an, damit
    nicht aus "Hallo Welt" ein "Hallo" wird.



  • 1. Genau wie beim ersten Element auch:

    Datei << Element1; 
    Datei << Element2;
    

    2. Das funktioniert also genau andersrum:

    Element Element1;
    Element Element2;
    
    Datei >> Element1; 
    Datei >> Element2;
    

    3. Speicher den std::string z.B. als eigene Zeile und lies ihn mit std::getline wieder aus.



  • hallo jjjjj
    VIelen Dank für deine Antwort.
    Leider funktioniert es noch nicht.

    Hier nochmals das angepasste Program:
    Die Klasse ist unverändert.

    int _tmain(int argc, _TCHAR* argv[])
    {
    element m,n;
    m.a=7;
    m.s="hallo";
    
    n.a=5;
    n.s="hello";
    
    std::ofstream os("Bla.txt");
    os << m;
    os<< n;
    os.close();
    
    std::ifstream stream("Bla.txt");
    element k,l;
    stream >> k;
    stream >>l;
    
    cout<<k.a<<"   "<<k.s<<endl;
    cout<<l.a<<"   "<<l.s<<endl;
    }
    

    Konsolenausgabe:
    7 hallo5hello
    -895993460

    Erst dachte ich, es läge daran, dass ich den String noch nicht so eingelesen habe, wie du es empfohlen hast und das Program deshalb nicht erkennt wo der string zu ende ist. Dann habe ich aber sämtliche Strings entfernt und einen Test gemacht. Hat aber nicht funktioniert.
    Was läuft da noch schief?



  • Probier mal:

    os << m << std::endl;
    os << n << std::endl;
    

    Ansonsten zeig nochmal den aktuellen Code (insbesondere die Operatoren >> und << in der Klasse)



  • Fantastisch! Jetzt klappts.

    Aber ich schreibe den String immer noch nicht als zeile in die datei. Kann dies späternoch zu problemen führen?



  • sulky schrieb:

    Fantastisch! Jetzt klappts.

    Aber ich schreibe den String immer noch nicht als zeile in die datei. Kann dies späternoch zu problemen führen?

    Durch das std::endl tust du das indirekt. Denn std::endl schreibt auch eine Leerzeile in die Datei.

    Ich habe dir in deinem anderen Thread dazu noch ausführlicher geantwortet. Am besten experimentierst du damit ein wenig rum und schaust dir auch mal die Datei Bla.txt an. Das sollte Klarheit schaffen.



  • Wieso ist mir das noch nicht aufgefallen?

    Einerseits können chars und ints unterschiedlich gross sein

    Nein, die Größe von char, signed char und unsigned char ist vom Standard deutlich festgelegt: Genau ein Byte.



  • Sone schrieb:

    Wieso ist mir das noch nicht aufgefallen?

    Einerseits können chars und ints unterschiedlich gross sein

    Nein, die Größe von char, signed char und unsigned char ist vom Standard deutlich festgelegt: Genau ein Byte.

    Quizfrage:

    Programm A speichert 60 Bytes in eine Datei.
    Programm B liest die gesamte Datei, findet aber nur 40 Bytes vor.
    Kann das sein?



  • reinterpreter schrieb:

    Sone schrieb:

    Wieso ist mir das noch nicht aufgefallen?

    Einerseits können chars und ints unterschiedlich gross sein

    Nein, die Größe von char, signed char und unsigned char ist vom Standard deutlich festgelegt: Genau ein Byte.

    Quizfrage:

    Programm A speichert 60 Bytes in eine Datei.
    Programm B liest die gesamte Datei, findet aber nur 40 Bytes vor.
    Kann das sein?

    Nein. Wenn Programm A 60 chars in die Datei schreibt, dann findet Programm B auch 60 vor.



  • Sone schrieb:

    reinterpreter schrieb:

    Sone schrieb:

    Wieso ist mir das noch nicht aufgefallen?

    Einerseits können chars und ints unterschiedlich gross sein

    Nein, die Größe von char, signed char und unsigned char ist vom Standard deutlich festgelegt: Genau ein Byte.

    Quizfrage:

    Programm A speichert 60 Bytes in eine Datei.
    Programm B liest die gesamte Datei, findet aber nur 40 Bytes vor.
    Kann das sein?

    Nein. Wenn Programm A 60 chars in die Datei schreibt, dann findet Programm B auch 60 vor.

    Doch. Da nicht festgelegt ist, aus wie vielen Bits ein Byte besteht. Bei Programm A sind es 8 Bits, bei Programm B 12 Bits.

    C++11-Standard § 1.7/1 schrieb:

    The fundamental storage unit in the C++ memory model is the byte. A byte is at least large enough to contain
    any member of the basic execution character set (2.3) and the eight-bit code units of the Unicode UTF-8
    encoding form and is composed of a contiguous sequence of bits, the number of which is implementation-
    defined. The least significant bit is called the low-order bit; the most significant bit is called the high-order
    bit. The memory available to a C++ program consists of one or more sequences of contiguous bytes. Every
    byte has a unique address.

    Wobei anzumerken ist, dass es höchst ungewöhnlich ist, dass an dieser Stelle ein Fehler passiert, aber es ist durchaus denkbar.



  • Ein 12-Bit-Byte Programm kann nicht auf einem 8-Bit-Byte File zugreifen. Weil ein 8-Bit-Byte File nur auf einer 8-Bit-Byte Plattform existieren, bzw. genutzt werden kann. Und diese kann keine 12-Bit-Byte Programme ausführen. (Denk mal darüber nach, wie grundlegend das eigentlich ist, worüber wir gerade schreiben)

    Edit: Ach, der Standard kennt ja keine Dateisysteme. Dann muss ich es direkter Formulieren. (Für alle, die den Text gelesen haben bevor er editiert wurde)


  • Mod

    Sone, es ist einfach falsch.

    (Aber realistisch ist die Annahme von 8-Bit chars natürlich schon. Man muss ganz schön suchen, um ein Gegenbeispiel zu finden)



  • SeppJ schrieb:

    Sone, es ist einfach falsch.

    Aber war dann mein Argument jetzt nicht richtig oder wie darf ich mir das merken..?


  • Mod

    Sone schrieb:

    SeppJ schrieb:

    Sone, es ist einfach falsch.

    Aber war dann mein Argument jetzt nicht richtig oder wie darf ich mir das merken..?

    Welches Argument genau meinst du? Ich möchte jetzt nicht den ganzen Thread durchlesen. Die Größe von char ist nicht festgelegt, das Padding ist nicht festgelegt, die Byteorder ist nicht festgelegt, usw. Eigentlich alles was ich Kellerautomat schon erklärt habe, warum ein direkt geschriebenes Binärformat so unportabel ist.



  • Sone schrieb:

    SeppJ schrieb:

    Sone, es ist einfach falsch.

    Aber war dann mein Argument jetzt nicht richtig oder wie darf ich mir das merken..?

    Wenn du deine letzte Auslassung meinst:

    Sone schrieb:

    Ein 12-Bit-Byte Programm kann nicht auf einem 8-Bit-Byte File zugreifen. Weil ein 8-Bit-Byte File nur auf einer 8-Bit-Byte Plattform existieren, bzw. genutzt werden kann.

    Quatsch.

    Sone schrieb:

    Und diese kann keine 12-Bit-Byte Programme ausführen.

    Irrelevant.

    Sone schrieb:

    (Denk mal darüber nach, [...]

    daß ein 12-bittiger char auf Platform A super in einen 16/32-bittigen int auf Platform B passt.

    Sone schrieb:

    Ach, der Standard kennt ja keine Dateisysteme.

    Jo. Wurscht.

    Sone schrieb:

    Dann muss ich es direkter Formulieren. (Für alle, die den Text gelesen haben bevor er editiert wurde)

    Vorher noch mehr Mist?



  • Wovon redest du?

    @Sone:
    Ok, Back to The Roots

    Nehmen wir mal ohne Beschränkung der Allgemeinheit an, wir möchten ein Struct serialisieren. Und wir machen es noch schlimmer: wir serialisieren nur C like Structs.

    typedef struct
    {
      char Name[20];
      char Nachname[30];
      int Alter;  
    } tPerson_V01;
    

    Wie sieht der entsprechende Serialisierungsbytecode aus ?

    0x0A|0x0A|0x0B|...		// Hier steht Name. Format: Byte 1: Anzahl der Bytes, Rest ASCII Daten 
    0x02|0x0A|0x0B			// Hier steht Nachname. Format: Byte 1: Anzahl der Bytes, Rest ASCII Daten 
    0x04|0x00|0x00			// Hier steht Alter. Format: Byte 1: Anzahl der Bytes, Rest Daten in Little Endian
    

    Das Programm speichert so die Daten ab und wird an den Kunden herausgeschickt. Nun will man aber das Struct erweitern.

    typedef struct
    {
      wchar_t Name[20];
      wchar_t Nachname[30];
      wchar_t Wohnorte[1024];
      int Alter;  
    } tPerson_V02;
    

    Und Peng. Wie soll nun das Format aussehen, damit du Dateien in denen tPerson_V01 steht als auch Dateien in denen tPerson_V02 einlesen kannst ? Etwas so ???

    0x00|0x0A|0x0A|0x0B|...		// Hier steht Name. Format: Byte 1-2: Anzahl der Bytes | Unicode Daten 
    0x00|0x02|0x0A|0x0B			// Hier steht Spitzname. Format: Byte 1-2: Anzahl der Bytes | ASCII Daten 
    0x02|0x00|0x00				// Hier steht Alter
    

    Ist aber leider völlig inkompatibel zu Format 1. Geschweige denn das in dem jetzigen Binärformat noch viele notwendigen Daten fehlen (Kodierung, Little Endian, Big Endian,...).

    Aber was tun, wenn beide Formate eingelesen werden sollen ? Ein Konvertierungstool schreiben ? Neues Struct, neues Tool ? Ala Autocad DXF, alle Jahre wieder ein neues Format ???

    Die Sünden der Vergangenheit, rächen sich bis in alle Ewigkeit.

    Du siehst, man braucht erstens ein Format zur Speicherung von Daten. Und zweitens muss man höllig auf Inkompatibilität aufpasssen. Und XML greift da einem schon unter die Arme, solche Fehler zu vermeiden.


Anmelden zum Antworten