Klasse in eine Binärdatei schreiben und wieder auslesen



  • Shade Of Mine schrieb:

    nimm ein struct-array oder noch besser einen vector<>

    Aber pack die ganzen einzelnen Elemente in eine struct - das macht den Code soviel besser.

    Dann kannst du auch die struct einfacher in eine datei speichern. wenn du zB char[] statt strings nimmst, haettest du structs mit fixer groesser. dann musst du nichtmal mehr alle daten im ram halten sondern kannst gezielt auf der datei operieren

    hm..
    Wenn ich das nun mit Hilfe von Structs realisieren will, wie kriege ich es dann hin, dass ich unendlich viele daten eingeben kann?



  • std::vector<STRUCT>



  • Thunaer schrieb:

    hm..
    Wenn ich das nun mit Hilfe von Structs realisieren will, wie kriege ich es dann hin, dass ich unendlich viele daten eingeben kann?

    wenn du eine struct Data hast, dann einfach:

    vector<Data> daten

    und du hast unendlich viele Daten die du benutzen kannst.
    Man kann dann auch schoen die einzelnen structs binaer in eine Datei schreiben - das erspart serialisierungscode. Alternativ, wenn du zB bei string bleiben willst, musst du der struct auch noch ein load() und save() spendieren.

    ein neuer eintrag in die datenbank geht dann so:

    Data d;
    d.x=1;
    d.y=2;
    d.z=3;
    //...
    daten.push_back(d);
    

    alles in eine datei schreiben geht dann so:

    vector<Data>::iterator i=daten.begin();
    vector<Data>::iterator e=daten.end();
    ofstream file(...);
    while(i!=e) {
      i->save(file);
    }
    

    ...



  • Sorry, wenn die Frage jetzt dumm ist, aber wie kann ich die Daten wieder ausgeben?
    Wenn ich es mit

    while(i!=e)
        {
             cout<<daten[i].nachname<<"|"<<daten[i].vorname<<"|"<<daten[i].strasse<<" "<<daten[i].hausnum<<endl;
        }
    

    versuche geht es nicht, weil er mir sagt:" no match for 'operator[]' in 'daten[i]' "



  • Was ist daten für ein Typ?



  • struct database
    {
    
        char vorname[255];
        char nachname[255];
        char strasse[510];
        char ort[255];
        int hausnum;
        int plz;
        int gebtag;
        int gebmonat;
        int gebjahr;
        int id;
    
    };
    

    und

    vector<database> Personendaten;
    

    Und personendaten wird an die entsprechende funktion übergeben..
    Hier der Prototyp:

    int show_eintrag(HANDLE stdOut, vector<database> daten, COORD xy);
    


  • Thunaer schrieb:

    ...

    while(i!=e)
    ...
    

    Hmmm, das sieht so ais, als würdest Du hier 2 Konzepte mischen: Iterator und Index.
    Dazwischen musst Du Dich entscheiden.
    (BTW: for-Schleifen sind ideal für sowas)

    Also entweder:

    for(size_t i=0; i<daten.size(); ++i) 
          cout<<daten[i].nachname<<"|"<<daten[i].vorname<<"|"<<daten[i].strasse<<" "<<daten[i].hausnum<<endl;
    

    oder

    for(vector<database>::const_iterator i=daten.begin(); i<daten.end(); ++i) 
          cout<<i->nachname<<"|"<<i->vorname<<"|"<<i->strasse<<" "<<i->hausnum<<endl;
    

    (Du siehst also: Iteratoren verwendet man wie Zeiger - genauergesagt sind "Zeiger" hier ein Sonderfall von Iteratoren)

    Noch ein paar Anmerkungen:
    1.) mach nicht zuviel "endl". kostet nur unnötig Performance. Zeilenumbruch geht prima mit '\n';
    2.) ich würde mir seeeeehr genau überlegen, ob ich WIRKLICH die Objekte im compilerspezifischen Binärformat ablegen will - denn das hat eine Menge Nachteile und IMHO nur sehr wenig Vorteile. Da gab's hier mal eine schöne Seite, auf die verwiesen wurde, aber den Link finde ich nicht mehr.
    3.) Denk daran, wie Parameter per value übergeben werden: Es wird eine Kopie angelegt, was bei größeren vector-en mächtig auf die Performance schlagen und bei ändernden Zugriffen zu unerwarteten Ergebnissen führen kann.
    4.) Wenn Du einen Parameter nicht ändern willst, deklariere ihn const. Das schafft Klarheit und Sicherheit.

    Gruß,

    Simon2.



  • struct database
    {
    
        char vorname[255];
        char nachname[255];
        char strasse[510];
        char ort[255];
        int hausnum;
        int plz;
        int gebtag;
        int gebmonat;
        int gebjahr;
        int id;
    
    };
    
    void show_eintrag(vector<database> const& daten){
    	for( size_t i=0; i<daten.size();i++)
        {
             cout<<daten[i].nachname<<"|"<<daten[i].vorname<<"|"<<daten[i].strasse<<" "<<daten[i].hausnum<<endl;
        }
    }
    
    int main()
    {
    	vector<database> Personendaten;
    	show_eintrag(Personendaten);
        return 0;
    }
    

    kompiliert bei mir ohne probleme



  • ohje schrieb:

    ...kompiliert bei mir ohne probleme

    Ich glaube ja auch nicht, dass sein Problem bei dem Typ von "daten" sondern bei dem von "i" liegt (siehe mein letztes Posting).

    Gruß,

    Simon2.



  • Hm ok danke!
    Die Eingabe und die Ausgabe funktioniert wunderbar bisher....
    Wenn ich aber versuche die Einträge so abzuspeichern gibt der Compiler mir einen Fehler aus....

    FILE *datei;
        if((datei = fopen("data.db", "wb")) == NULL)
        {
             fflush(stdin);
             cout<<"Datei konnte nich geoeffnet werden!"<<endl;
             cin.get();
        }
        else
        {
             fwrite(daten, sizeof(struct database), daten.size(), datei); 
        }
        fclose(datei);
    

    Der Fehler:

    cannot convert `std::vector<database, std::allocator<database> >' to `const void*' for argument `1' to `size_t fwrite(const void*, size_t, size_t, FILE*)'
    

    Wäre nett wenn ihr mir mal wieder helfen könntet

    mfg

    Edit:
    Hm, warum funktioniert das nich:

    database *tmp;
       size_t i;
       int x = 0;
       for(i=0; i<daten.size(); ++i)
        {
             strcpy(tmp[x].nachname, daten[i].nachname);
             strcpy(tmp[x].ort, daten[i].ort);
             strcpy(tmp[x].strasse, daten[i].strasse);
             strcpy(tmp[x].vorname, daten[i].vorname);
             tmp[x].gebjahr = daten[i].gebjahr;
             tmp[x].gebmonat = daten[i].gebmonat;
             tmp[x].gebtag = daten[i].gebtag;
             tmp[x].hausnum = daten[i].hausnum;
             tmp[x].id = daten[i].id;
             tmp[x].plz = daten[i].plz;
             x++;
        }
    


  • Achso was ich noch sagen wollte:
    Der Compiler gibt mir beim letzteren Code keinen Fehler aus, sondern die *.exe schmiert an der Stelle des ersten strcpy ab....



  • Hi,

    mein Tipp: Lass' es !!

    (das "Binärspeichern") 😉
    Du hast eigentlich scohn alles, was Du brauchst: So wie Du Deine Objekte auf Konsole ausgibst, kannst Du sie auch in eine Datei ausgeben und wieder einlesen.
    Das einzige, was Du tun musst, ist, mit dem operator<<() in einen ofstream statt nach cout zu "schieben"....

    Glaub mir: Es hat zahllose Vorteile und (für Dich) keine Nachteile....

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Hi,

    mein Tipp: Lass' es !!

    (das "Binärspeichern") 😉
    Du hast eigentlich scohn alles, was Du brauchst: So wie Du Deine Objekte auf Konsole ausgibst, kannst Du sie auch in eine Datei ausgeben und wieder einlesen.
    Das einzige, was Du tun musst, ist, mit dem operator<<() in einen ofstream statt nach cout zu "schieben"....

    Glaub mir: Es hat zahllose Vorteile und (für Dich) keine Nachteile....

    Gruß,

    Simon2.

    Hm ja.
    Das Problem ist nur, dass es ein Projekt für die Schule ist, welches benotet wird und der Lehrer Binärdateien fordert....
    Was wir machen konnten wir uns aussuschen, es sollten aber aufjedenfall:
    1. Daten in Binärdateien geschrieben ausgelesen werden
    2. Sortier und Suchalgorythmen vorhanden sein

    Ich würde es mit Binärdateien ja liebend gerne lassen, aber es geht ja leider nicht....



  • Hab meinen fehler schon selber gefunden, war wirklich dumm irgendwie ^^

    Das hat gefehlt:

    tmp = new database[daten.size()];
    


  • Thunaer schrieb:

    ...
    Hm ja.
    Das Problem ist nur, dass es ein Projekt für die Schule ist, welches benotet wird und der Lehrer Binärdateien fordert...

    OK - da kann man nichts machen.

    Dein Ansatz mit fwrite() ist an sich schon nicht schlecht, aber Du musst genau betrachten, was Du speichern willst:
    - das vector-Objekt (also alle Verwaltungsinformationen),
    - die einzelnen Elemente hier also die "database-Objekte".
    Stell Dir einfach mal eine Simpelimplementation von vector vor:

    class vector {
       database* elemente;
       size_t anzahl;
    public:
       database& operator[](size_t i) { return elemente[i]; }
       size_t size() { return anzahl; }
    };
    

    Wenn Du nun diesen vector abspeicherst, kommt in die Datei lediglich ein Zeiger und ein size_t ... was Dir wahrscheinlich nicht reichen wird.
    (mit string hättest Du dasselbe Problem - bei Deiner database-Klasse hast Du das "Glück", dass sie ihre Daten als char-Arrays halten).
    Wenn Du das also "binär" speichern willst, solltest Du die Elemente einzeln durchgehen und jedes einzelne "weg-fwrite-n".

    Gruß,

    Simon2.

    P.S.: Vielleicht kannst Du mal Deinen Lehrer auf die Probleme mit dem "Binärspeichern" hinweisen ... natürlich erst, wenn Du Deine Note eingesackt hast. 😉


Anmelden zum Antworten