speichern von Ojekten?

Dieses Thema speichern von Ojekten? im Forum "Webentwicklung, Hosting & Programmierung" wurde erstellt von luzidius, 16. Sep. 2005.

Thema: speichern von Ojekten? Hallo forum, ich schreibe aus indien, wo ich eine software zur erstellung von Stundenplaenen fuer ein Slumschule...

  1. Hallo forum,

    ich schreibe aus indien, wo ich eine software zur erstellung von Stundenplaenen fuer ein Slumschule programmiere.

    Dazu moechte ich objekte von der klasse Teacher in einer verketteten liste verwalten und die einzelnen ojekte binaer abspeichern.

    Beispiel fuer die klasse Teacher:

    class Teacher
    {
    char* name
    Teacher* next
    }


    Dann habe ich, um das schreiben und lesen auszuprobieren, zwei funktionen formuliert:

    Schreiben()
    {
    char* pszFileName = c:\\test\\myfile.dat;
    CFile myFile;
    CFileException fileException;


    if ( !myFile.Open( pszFileName, CFile::modeCreate |
    CFile::modeReadWrite ), &fileException )
    {
    TRACE( Can't open file %s, error = %u\n,
    pszFileName, fileException.m_cause );
    }

    Teacher* teach= new Teacher
    teach->name=test;

    myFile.Write( &teach, sizeof( class Teacher ) );

    myFile.Close();


    }


    Naechste funktion zum lesen der daten:

    Lesen()
    {

    char* pszFileName = c:\\test\\myfile.dat;
    CFile myFile;
    CFileException fileException;
    UINT nActual = 0;
    Teacher* temp;

    if ( !myFile.Open( pszFileName, CFile::modeReadWrite ), &fileException )
    {
    TRACE( Can't open file %s, error = %u\n,
    pszFileName, fileException.m_cause );
    }

    myFile.SeekToBeginn();

    nActual = myFile.Read( &temp, sizeof( class Teacher ) );

    AfxMessageBox(test);
    myFile.Close();

    }


    Wenn ich das programm starte und einen Teacher einlese, und danach, aber waehrend der selben laufzeit die funktion Lesen() aufrufe, wird die AfxMessageBox(test) angezeigt.

    Schliese ich die anwendung, starte sie neu und rufe die lesen funktion auf zeigt die AfxMessageBox nichts mehr an; Als waere der name nur noch .
    Die myFile.dat, ist aber immernoch beschrieben.
    Ich habe das selbe vorher mit fopen, fread, fwrite usw. versucht. Gab den selben fehler.

    weis jemand woran das liegen koennnte, ich schmohre naehmlich aschon seit tagen auf diesem problem?
     
  2. Ich nehme mal an, du hast das jetzt aus dem Gedächtnis getippt? Denn so wird es sicher nicht kompiliert ...

    Wenn ich dazu komme, schreibe später ich noch ein paar Sachen, die dir vielleicht weiterhelfen.

    Aber auf die Schnelle:

    Code:
    class Teacher
    {
    public: // geht sonst so eh nicht
      char* name;
      Teacher* next;
    };
    
    ...
    myFile.Write( &teach, sizeof( class Teacher ) ); 
    ...
    nActual = myFile.Read( &temp, sizeof( class Teacher ) ); 
    ...
    
    In Teacher stehen 2 Zeiger. sizeof( class Teacher ) gibt die Größe der beiden Zeiger an.
    Du willst aber sicher den Namen des Lehres in der Datei speichern und nicht 2 Zeiger ...
    Das Speichern des next-Zeigers würde dir auch nichts bringen, denn die Liste ist ja eine dynamische Datenstruktur.  Du kannst die ganzen Einträge mit next später nicht einfach wieder laden und - schwupps - ist die Liste wieder hergestellt ... (Du hast ja noch keine Liste, aber das schon vorweg.)
    myFile.Write( &teach, sizeof( class Teacher ))
    teach ist auch schon ein Zeiger, &teach ist ein Zeiger auf einen Zeiger. Darum ist das:

    auch nur ein dummer Zufall. Du schreibst die Adresse des Objektes in die Datei und liest sie dann gleich wieder; deswegen zeigt teacher in Lesen() auch wieder auf das gleiche Objekt im Speicher. Das Programm könnte sogar abstürzen, denn du versucht in Lesen(), 8 Byte aus der Datei [sizeof(class Teacher)] in 4 Byte [temp] zu schreiben (und in Schreiben() liest du aus dem Speicher 4 Byte hinter->teach').
     
  3. Ich habe versucht was aus deinen ratschlaegen zu machen, bin aber nicht weit gekommen.

    koenntest du mir bitte ein beispiel dafuer geben, wie ich objekte von der Klasse Teacher binaer speichern und auslesen kann, damit ich sie nach dem einlesen in eine liste einfuege.

    class Teacher
    {
    public:
    char getname();
    void setname(char nam[30]);
    void setnext( Teacher* nex)
    char name[30];
    Teacher* next;
    BOOL a, b, c;

    };

    danke
    alex
     
  4. Das waren ja noch keine Ratschläge, sondern bloß eine Beschreibung der Fehlerursache  ... :)

    Klar, mache ich nachher.

    // Edit

    Sry, bin nicht mehr dazu gekommen. Montag ...
     
  5. Gleich vorweg: Bitte nicht selbst mit Listen u.ä. rumfummeln, sondern MFC- oder STL-Collections verwenden. Ich weiss nicht, welcher Kompiler bzw. welche MFC- und STL-Version dir zur Verfügung steht und ob damit alles so funktioniert. Wenn nicht (oder wenn du weitere Fragen hast), melde dich einfach.

    In einer echten Anwendung (u.a.):
    - Intensivere Fehlerprüfung und Testen auf Plausibilität der geladenen Daten
    - Statt C-Strings besser std::string oder CString der MFC verwenden
    - Evtl. CArchive verwenden, wie in der MFC Document-View-Architektur vorgesehen
    - Ein kleiner Header ist praktisch (Kennzeichen, z.B. TCH, Anzahl der Objekte und Versionsnummer)
    - Gegebenenfalls andere MFC- bzw STL-Container verwenden, wenn sinnvoll
    - Über XML nachdenken
    - Je nach Umfang der Daten über ein (kostenloses) Datenbanksystem nachdenken

    Code:
    // Zusammengestoppelte Teacher-Klasse als Beispiel
    class Teacher
    {
    private:
      enum {WhatEverLen= 3, MaxNameLen= 30}; // nötig für VC6 und kleiner
      char name[MaxNameLen];
      bool whatever[WhatEverLen]; // statt a, b, c
      int  shoesize; // als Beispiel ;)
      void arrinit();
    public:
      Teacher();
      Teacher(const char* name);
      Teacher(const char* name, int shoesize);
      const char* getName() const;
      void setName(const char* const);
      int  getShoeSize();
      void setShoeSize(int);
      bool getWhatEver(int idx);
      void setWhatEver(int idx, bool value);
      bool operator== (const Teacher&);
      bool operator< (const Teacher&); // Zum Sortieren (optional)
      friend ostream& operator<< (ostream& os, const Teacher&);
      friend istream& operator>> (istream& is, Teacher& teacher);
    };
    
    Hinweis: Wenn du den Speicher für->name' mit new allokieren würdest
    class Teacher
    {
    private:
      char* name;
    ...
    name= new char[length];
    ...
    oder generell etwas anderes als einfache Variablen und Arrays in der Klasse vorhanden wäre, würde sich einiges ändern. Du solltest dann u.a. den Default-Konstruktor ändern und einen Copy-Konstruktor sowie einen Zuweisungs-Operator schreiben. Sonst kannst du z.B. Teacher-Objekte nicht fehlerfrei kopieren. Auch das Schreiben und Lesen der Daten müsste teilweise etwas anders implementiert werden, da, wenn du in diesem Fall einfach das Objekt als ganzes speicherst, wieder nur Zeiger statt Daten gespeichert würden.

    Code:
    #include stdafx.h
    
    #include <fstream>
    #include <list>             // für std::list
    #include <afxtempl.h> // für CList
    
    using namespace std;
    
    bool copyStr(char* target, const char* source, unsigned int targetLen);
    
    Code:
    Teacher::Teacher()
      : shoesize(0) {
      arrinit();
    }
    
    Teacher::Teacher(const char* _name, int _shoesize)
      : shoesize(_shoesize) {
      arrinit();
      copyStr(name, _name, MaxNameLen); // oder Exception, wenn false
    }
    
    Teacher::Teacher(const char* const _name)  : shoesize(0) {
      arrinit();
      copyStr(name, _name, MaxNameLen); // oder Exception, wenn false
    }
    
    void Teacher::arrinit() {
      name[0]=->\0';
      for(int widx= 0; widx < WhatEverLen; ++widx)
        whatever[widx]= false;
    }
    
    bool Teacher::operator== (const Teacher& rhs)
    {
      // Beispiel: Identisch, wenn gleiche Namen und gleiche Schuhgröße -
      // du musst dann eigene Bedingungen festlegen.
      return (strcmp(name, rhs.name) || (shoesize != rhs.shoesize) ? false : true);
    }
    
    bool Teacher::operator< (const Teacher& rhs)
    {
      // Vergleich nach Namen
      return (strcmp(name, rhs.name) < 0 ? true : false);
    }
    
    const char* Teacher::getName() const {
      return name;
    }
    
    void Teacher::setName(const char* _name) {
      if(!copyStr(name, _name, MaxNameLen))
        throw(Teacher::setName - string error); // Bsp., dann richtige Exceptions
    }
    
    int Teacher::getShoeSize() {
      return shoesize;
    }
    
    void Teacher::setShoeSize(int ssi) {
      shoesize= ssi;
    }
    
    bool Teacher::getWhatEver(int idx)
    {
      if(idx > WhatEverLen-1)
        throw(Teacher::getWasauchimmer - index error);
      return whatever[idx];
    }
    
    void Teacher::setWhatEver(int idx, bool value) {
      if(idx > WhatEverLen-1)
        throw(Teacher::setWasauchimmer - index error);
      whatever[idx]= value;
    }
    
    ostream& operator<< (ostream& os, const Teacher& teacher) {
      os << teacher.name <<->\n'; // mit echter Länge statt dem komplettem Array
      os.write((char*)&teacher.whatever, sizeof teacher.whatever);
      os.write((char*)&teacher.shoesize, sizeof teacher.shoesize);
      return os;
    }
    
    istream& operator>> (istream& is, Teacher& teacher) {
      is.getline(teacher.name,->\n'); // natürlich hier dann auch korrekt lesen
      is.read((char*)&teacher.whatever, sizeof teacher.whatever);
      is.read((char*)&teacher.shoesize, sizeof teacher.shoesize);
      return is;
    }
    
    bool copyStr(char* target, const char* source, unsigned int targetLen)
    {
      if((!source) || (strlen(source) > targetLen-1))
        return false;
      strcpy(target, source);
      return true;
    }
    
    Code:
    void TestMFC()
    {
      // Liste erstellen
      CList<Teacher, const Teacher&> tlist;
      tlist.AddTail(Teacher(Michael, 57));
      tlist.AddTail(Teacher(Frank,  38));
      tlist.AddTail(Teacher(Mary, 39));
    
      // Schreiben
    
      CFile outfile;
      CFileException ex;
      CString filename(e:\\temp\\test.dat);
    
      if (!outfile.Open(filename, CFile::modeWrite |
        CFile::shareExclusive | CFile::modeCreate, &ex))
      {
        TCHAR szError[1024];
        ex.GetErrorMessage(szError, 1024);
        AfxMessageBox(szError);
        return;
      }
    
      try {
        POSITION pos = tlist.GetHeadPosition();
        for (int i=0; i < tlist.GetCount(); ++i) {
          Teacher t= tlist.GetNext(pos);
          // Hier schreiben wir im Gegensatz zu operator<< feste Blockgrößen
          // (ginge mit operator<< natürlich auch)
          outfile.Write(&t, sizeof(t));
        }
      }
      catch(CFileException* pEx) {
        pEx->ReportError();
        outfile.Close();
        return;
      }
      outfile.Close();
    
      // Lesen
    
      CList<Teacher, const Teacher&> tlist2;
      CFile infile;
    
      if (!infile.Open(filename, CFile::modeRead
        | CFile::shareDenyNone, &ex)) {
        TCHAR szError[1024];
        ex.GetErrorMessage(szError, 1024);
        AfxMessageBox(szError);
        return;
      }
    
      try {
        UINT size= sizeof(Teacher);
        UINT read;
        for(;;) {
          Teacher t;
          read= infile.Read(&t, size);
          if(read == size)
            tlist2.AddTail(t);
          else
            break;
        }
        if(read > 0) { // Darf nicht sein beim letzten Lesevorgang
          AfxThrowFileException(CFileException::endOfFile, -1, filename);
        }
      }
      catch(CFileException* pEx) {
        pEx->ReportError();
        infile.Close();
        return;
      }
      infile.Close();
    
      // Teacher-Daten anzeigen (Namen)
      POSITION pos = tlist2.GetHeadPosition();
      CString str;
      for (int i=0; i < tlist2.GetCount(); ++i) {
        Teacher t= tlist2.GetNext(pos);
        str+= t.getName();
        str+= \n;
      }
      AfxMessageBox(str);
    
    }
    
    Code:
    void TestSTL()
    {
      // Liste erstellen
      list<Teacher> tlist;
      tlist.push_back(Teacher(Michael, 57));
      tlist.push_back(Teacher(Frank,  38));
      tlist.push_back(Teacher(Mary, 39));
    
      char filename[]= e:\\temp\\test.dat;
    
      // Liste in eine Datei schreiben
      try {
    
        tlist.sort(); // Nur als Beispiel, was man ohne großen Aufwand mit der STL machen
                      // kann; dazu ist operator< in Teacher nötig.
    
        ofstream outfile;
        outfile.open(filename, ios::out);
        if(!outfile.is_open())
          throw Kann Datei nicht zum Schreiben oeffnen;
    
        ostream_iterator<Teacher> output(outfile, );
    
        copy(tlist.begin(), tlist.end(), output);
    
        outfile.close();
    
        // Alternativ könnten wir auch über die Liste iterieren (ähnlich wie unten
        // bei Liste anzeigen) und einzeln die Teacher-Objekte
        // per << nach outfile schreiben:
        /*
        list<Teacher>::const_iterator pos;
          for (pos = tlist.begin(); pos != tlist.end(); ++pos)
            outfile << *pos;
        */
      }
      catch(char *str) {
        AfxMessageBox(str);
        return;
      }
    
      // Alternativ könnten wir auch über die Liste iterieren und einzeln
      // die Teacher-Objekte per >> von infile lesen.
    
      // Liste lesen
    
      list<Teacher> tlist2;
      // Wir könnten auch tlist leeren [tlist.clear()] und hier verwenden. Ohne clear()
      // würde die neuen Objekte zu den 3 alten hinzugefügt.
    
      try {
    
        ifstream infile;
        infile.open(filename, ios::in);
        if(!infile)
          throw Kann Datei nicht zum Lesen oeffnen;
    
        istream_iterator<Teacher> input(infile);
        istream_iterator<Teacher> eof;
    
        copy(input, eof, back_inserter(tlist2));
    
        // Alternativ könnten wir auch über die Liste iterieren und einzeln
        // die Teacher-Objekte per >> von infile lesen.
      }
      catch(char *str) {
        AfxMessageBox(str);
        return;
      }
    
      // Teacher-Daten anzeigen (Namen)
      list<Teacher>::const_iterator pos;
      char str[200];
      strcpy(str, Objekte:\n);
      for (pos = tlist2.begin(); pos != tlist2.end(); ++pos) {
        strcat(str, pos->getName());
        strcat(str, \n);
      }
      AfxMessageBox(str); 
    
    }
    
     
Die Seite wird geladen...

speichern von Ojekten? - Ähnliche Themen

Forum Datum
Ergebnis einer Google-suche speichern in Favoriten-liste Windows 8 Forum 3. Dez. 2016
CorelDraw übernimmt nicht mehr den Namen der Datei beim Abspeichern Software: Empfehlungen, Gesuche & Problemlösungen 30. Juni 2015
Speichern unter trotz Adminrechten nicht möglich Windows 7 Forum 1. Mai 2015
In Telefon und Modem lässt sich nichts abspeichern Windows 7 Forum 11. Apr. 2015
Outlook 2010 - Ordnerstruktur mit Mails speichern (nicht als PST) Microsoft Office Suite 26. Jan. 2015