Klasse in eine Binärdatei schreiben und wieder auslesen



  • Hallo!
    Ich habe hier folgende Klasse:

    class database
    {
    	private:
    		string *vorname, *nachname, *strasse, *ort;
    		int *plz, *hausnum, *gebtag, *gebmonat, *gebjahr;
    		int max;
    		int index;
    		static const int ERHOEHEN = 5;//Datensatz wird um diesen Wert erweitert, wenn er voll ist	
    	public:
    		database(int start)
    		{
    			max = start; //Maximalanzahl der Datensätze
    			vorname = new string[max];
    			nachname = new string[max];
    			strasse = new string[max];
    			ort = new string[max];
    			plz = new int[max];
    			hausnum = new int[max];
    			gebtag = new int[max];
    			gebmonat = new int[max];
    			gebjahr = new int[max];
    			index = -1; //Indexcounter
    		}
    
    		~database()
    		{
    			delete [] vorname;
    			delete [] nachname;
    			delete [] strasse;
    			delete [] ort;
    			delete [] plz;
    			delete [] hausnum;
    			delete [] gebtag;
    			delete [] gebmonat;
    			delete [] gebjahr;
    		}
    
    		void add(string ein_vorname, string ein_nachname, string ein_strasse, string ein_ort, int ein_plz, int ein_hausnum, int ein_gebtag, int ein_gebmonat, int ein_gebjahr)
    		{
    			++index;
    			if(index == max)
    			{
    			    max += ERHOEHEN;
    
    			    //Temporärvariablen zur Speicherung der bisherigen Dateien anlegen
    			    string *tmp_vorname = vorname;
                    string *tmp_nachname = nachname;
                    string *tmp_strasse = strasse;
                    string *tmp_ort = ort;
                    int *tmp_plz = plz;
                    int *tmp_hausnum = hausnum;
                    int *tmp_gebtag = gebtag;
                    int *tmp_gebmonat = gebmonat;
                    int *tmp_gebjahr = gebjahr;
    
                    //neue Speicheranlegung 
                    vorname = new string[max];
                    nachname = new string[max];
                    strasse = new string[max];
                    ort = new string[max];
                    plz = new int[max];
                    hausnum = new int[max];
                    gebtag = new int[max];
                    gebmonat = new int[max];
                    gebjahr = new int[max];
    
                    //temporäre Daten in die Datensätze schreiben
                    for(int i = 0; i<index; i++)
                    {
                        vorname[i] = tmp_vorname[i];
                        nachname[i] = tmp_nachname[i];
                        strasse[i] = tmp_strasse[i];
                        ort[i] = tmp_ort[i];
                        plz[i] = tmp_plz[i];
                        hausnum[i] = tmp_hausnum[i];
                        gebtag[i] = tmp_gebtag[i];
                        gebmonat[i] = tmp_gebmonat[i];
                        gebjahr[i] = tmp_gebjahr[i];
                    }
    
                    //Temporäre Daten löschen, denn sie verbauchen ne Menge Speicher
                    delete [] tmp_vorname;
        			delete [] tmp_nachname;
        			delete [] tmp_strasse;
        			delete [] tmp_ort;
        			delete [] tmp_plz;
        			delete [] tmp_hausnum;
        			delete [] tmp_gebtag;
        			delete [] tmp_gebmonat;
        			delete [] tmp_gebjahr;
    			}
    
    			vorname[index] = ein_vorname;
                nachname[index] = ein_nachname;
                strasse[index] = ein_strasse;
                ort[index] = ein_ort;
                plz[index] = ein_plz;
                hausnum[index] = ein_hausnum;
                gebtag[index] = ein_gebtag;
                gebmonat[index] = ein_gebmonat;
                gebjahr[index] = ein_gebjahr;
    
    		}
    
    		void entfehrnen(int stelle) //Entfehrnt Daten an einer Bestimmten Stelle
    		{
                if(stelle<=index)
                {
                    string tmp_vorname[index]; 
                    string tmp_nachname[index]; 
                    string tmp_strasse[index]; 
                    string tmp_ort[index]; 
                    int tmp_plz[index]; 
                    int tmp_hausnum[index]; 
                    int tmp_gebtag[index]; 
                    int tmp_gebmonat[index]; 
                    int tmp_gebjahr[index]; 
                }
            }
    
    		string get_vorname(int stelle) //Daten an der bestimmten Stelle zurückgeben
    		{
                if(stelle<=index)
                {
                    return vorname[stelle];
                }
                else
                {
                    return "Fehler!";
                }
            }
    
            string get_nachname(int stelle)
    		{
                if(stelle<=index)
                {
                    return nachname[stelle];
                }
                else
                {
                    return "Fehler!";
                }
            }
    
            string get_strasse(int stelle)
    		{
                if(stelle<=index)
                {
                    return strasse[stelle];
                }
                else
                {
                    return "Fehler!";
                }
            }
    
            string get_ort(int stelle)
    		{
                if(stelle<=index)
                {
                    return ort[stelle];
                }
                else
                {
                    return "Fehler!";
                }
            }
    
            int get_plz(int stelle)
    		{
                if(stelle<=index)
                {
                    return plz[stelle];
                }
                else
                {
                    return -1;
                }
            }
    
            int get_hausnum(int stelle)
    		{
                if(stelle<=index)
                {
                    return hausnum[stelle];
                }
                else
                {
                    return -1;
                }
            }
    
            int get_gebtag(int stelle)
    		{
                if(stelle<=index)
                {
                    return gebtag[stelle];
                }
                else
                {
                    return -1;
                }
            }
    
            int get_gebmonat(int stelle)
    		{
                if(stelle<=index)
                {
                    return gebmonat[stelle];
                }
                else
                {
                    return -1;
                }
            }
    
            int get_gebjahr(int stelle)
    		{
                if(stelle<=index)
                {
                    return gebjahr[stelle];
                }
                else
                {
                    return -1;
                }
            }
    
            int get_index()
            {
                return index;
            }    
    
    };
    

    Nun würde ich gerne alle Daten (vorname, nachname, strasse, ort,plz, hausnum, gebtag, gebmonat, gebjahr) in eine Binärdatei speichern und sie beim nächsten Programmstart alle auch wieder einlesen können....
    Leider weiß ich ncih, wie ich das anstellen könnte.

    mfg



  • std::vector statt normals array
    std::ofstream

    Aber überleg dir mal ob du bei deinem Code nicht was umstellen solltest.
    z.B. std::vector< std::vector<string> >
    get...
    return daten[NAME][index]



  • 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



  • 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. 😉


Log in to reply