tutorials.de Buch-Aktion 05/2012
ERLEDIGT
JA
ANTWORTEN
7
ZUGRIFFE
506
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Orthak Orthak ist offline Mitglied Bronze
    Registriert seit
    Dec 2008
    Beiträge
    36
    Hallo,
    ich arbeite daran C++ structs in Binärform zu lesen und zu schreiben. Ersteres funktioniert ganz gut, doch das Lesen bereitet mir Probleme.

    Folgend meine bisherigen Funktionen:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    writeBinary(QATuple tuple, const char* fileName) {
     
        fstream binary_file(fileName, ios::out|ios::binary|ios::app);
     
        if(binary_file == NULL)
            return false;
     
        binary_file.write(reinterpret_cast<char*>(&tuple),sizeof(QATuple));
        binary_file.close();
     
        printf("Objektadresse: %p | Dateiname: %s\n", &tuple, fileName);
        return true;
    }
     
    readBinary(const char* fileName) {
     
        QATuple p_Data;
        fstream binary_file(fileName,ios::binary|ios::in);
     
        if(binary_file == NULL)
            return false;
     
        binary_file.read(reinterpret_cast<char*>(&p_Data),sizeof(QATuple));
        binary_file.close();
     
        printf("Frage: %s\n", p_Data.question.c_str());
        return true;
    }

    So lese ich allerdings immer nur ein struct aus.
    Ich denke am sinvollsten ist es den Lesezeiger jedes Mal um sizeof(QATuple) zu verschieben bis Dateiende. Jedes mal wenn dieser Vorgang abgeschlossen wird, wird das Ergebnis in zB. einen Vektor geschrieben und dieser dann zurückgegeben.

    Leider gelingt es mir nicht wirklich den Zeiger entsprechend zu verschieben. Hat jemand eine Idee wie man das (so oder auch anders) realisieren könnte?

    P.S.: Code der struct:
    Code :
    1
    2
    3
    4
    5
    
    typedef struct questionAnswersTuple {
        string question;
        string answer;
        string wrongAnswers[3];
    } QATuple;
     

  2. #2
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Hi.
    Zitat Zitat von Orthak Beitrag anzeigen
    ich arbeite daran C++ structs in Binärform zu lesen und zu schreiben. Ersteres funktioniert ganz gut, doch das Lesen bereitet mir Probleme.
    Du widersprichst dir irgendwie selbst. Wobei hast du denn nun Probleme?
    Zitat Zitat von Orthak Beitrag anzeigen
    Ich denke am sinvollsten ist es den Lesezeiger jedes Mal um sizeof(QATuple) zu verschieben bis Dateiende. Jedes mal wenn dieser Vorgang abgeschlossen wird, wird das Ergebnis in zB. einen Vektor geschrieben und dieser dann zurückgegeben.
    Meiner Meinung nach wäre es am sinnvollsten die Datei nicht ständig zu öffnen und zu schließen.

    Öffne die Datei zu Beginn des Programms, lies die Daten in einen std::vector ein, manipuliere die Daten im Vektor und speichere den Vektor am Ende wieder in der Datei ab.

    Gruß
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  3. #3
    SGSSGene SGSSGene ist offline Mitglied Gold
    Registriert seit
    Feb 2008
    Beiträge
    124
    Bist du dir sicher, das das schrieben funktioniert?
    Das Problem liegt vermutlich an der Klasse "string" und wie sie intern aufgebaut ist.
    Ich versuche dir mal das Problm anhand eines anderen Beispiel zu erklären.
    angenommen du hast folgendes Struct:
    Code :
    1
    2
    3
    
    typdec struct a{
    float *ptr;
    } A;
    Würdest du dieses Struct "Binär" schireben, würde nicht eine FLießkomma Zahl geschrieben, werden, sondern die Adresse wo sich der Zeiger befindet.

    Un genau das ist auch das Problem bei "string" intern arbeiten diese mit Zeigern, weshalb du Speicheraddressen in deine Datei schreibst. Beim auslesen sind diese Adressen leiderwertlos.

    mfg
    Gene
     

  4. #4
    Orthak Orthak ist offline Mitglied Bronze
    Registriert seit
    Dec 2008
    Beiträge
    36
    Zitat Zitat von deepthroat Beitrag anzeigen
    Du widersprichst dir irgendwie selbst. Wobei hast du denn nun Probleme?
    Stimmt, das klingt irgendwie unlogisch. Letzteres wäre das richtige Wort gewesen .

    lies die Daten in einen std::vector ein
    Genau dort liegt mein Problem. Wie genau setze ich das am besten um? Meine bisherigen Versuche waren leider nicht sehr erfolgreich. Ist mein bisheriger Ansatz (um sizeof(QATuple) weiterspringen) überhaupt praktikabel?

    Bist du dir sicher, das das schrieben funktioniert?
    Auch wenn ich mich mit dem Aufbau der string Klasse nicht so gut auskenne, hatte ich selbige Befürchtung. Erstaunlicherweise klappt es ganz gut. Die Zeile
    Code :
    1
    
    printf("Frage: %s\n", p_Data.question.c_str());
    liefert wie erhoft den geschriebenen Wert der ersten struct (siehe Ende von readBinary).
     

  5. #5
    Avatar von devDevil
    devDevil devDevil ist offline Mitglied Platin
    Registriert seit
    Jun 2005
    Beiträge
    662
    Hmm dann beende bitte mal dein Programm oder leer zwischendurch mal deinen Speicher Das Funktioniert nur weil zufällig noch die alte Speicheradresse nicht übershrieben wurde und du somit glück hast und deine Zeiger szs. noch "gültig" sind, auch wenn dies in keinem Std. steht dass das so sein soll/muss.
     

  6. #6
    Orthak Orthak ist offline Mitglied Bronze
    Registriert seit
    Dec 2008
    Beiträge
    36
    Hmm dann beende bitte mal dein Programm oder leer zwischendurch mal deinen Speicher
    Schade, das Program muss sich die Daten wirklich irgendwo aus dem Speicher geholt haben, denn nach einem Neustart funktioniert es tatsächlich nicht mehr .

    Unabhängig davon habe ich die Funktionen soweit umgebaut das sie vektorweise Daten in Binärform lesen und schreiben können. Hier einmal das komplette Listing:

    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    
    #include <iostream>
    #include <fstream>
    #include <vector>
     
    using namespace std;
     
    // Variablen
    typedef struct qaTuple {
        char question[10];
        char answer[10];
    } Tuple;
     
    vector<Tuple> paare;
     
    // Schreiben
    bool writeBinary(vector<Tuple> paare, const char* fileName) {
     
        // Stream fuer binaeres Schreiben
        fstream binary_file(fileName, ios::out|ios::binary|ios::app);
     
        // Fehler, abbruch
        if(binary_file == NULL)
            return false;
     
        vector<Tuple>::iterator I = paare.begin();
        while(I != paare.end()) {
            binary_file.write(reinterpret_cast<char*>(&(*I)),sizeof(Tuple));
            printf("Objektadresse: %p | Dateiname: %s\n", &(*I), fileName);
            ++I;
        }
     
            binary_file.close();
        return true;
    }
     
    // Lesen
    vector<Tuple> readBinary(const char* fileName) {
     
        Tuple p_Data;
        vector<Tuple> filePaare;
        fstream binary_file(fileName, ios::binary|ios::in);
     
        if(binary_file == NULL)
            return filePaare;
     
        while(!binary_file.eof()) {
            binary_file.read(reinterpret_cast<char*>(&p_Data),sizeof(Tuple));
            filePaare.push_back(p_Data);
        }
     
        binary_file.close();
        filePaare.pop_back();
        
        return filePaare;
    }
     
     
    int main() {
     
        Tuple t1 = {
                "frage1",
                "antwort1"
        }; paare.push_back(t1);
     
        Tuple t2 = {
                "frage2",
                "antwort2"
        }; paare.push_back(t2);
     
        Tuple t3 = {
                "frage3",
                "antwort3"
        }; paare.push_back(t3);
     
        writeBinary(paare, "test.dat");
     
        vector<Tuple> gelPaare = readBinary("test.dat");
        vector<Tuple>::iterator I = gelPaare.begin();
        printf("Anzahl der Paare: %i\n\n", gelPaare.size());
        int counter = 1;
        while(I != gelPaare.end()) {
            printf("%i: Frage: %s | Antwort: %s\n", counter, (*I).question, (*I).answer);
            ++I;
            counter++;
        }
     
        return 1;
    }
    Zeile 52 macht mir noch etwas Sorgen. Doch ohne sie ist das letzte struct doppelt enthalten.

    In dieser Testanwendung habe ich allerdings auf strings in der struct verzichtet. Hat vielleicht Jemand einen Tip wie ich diesen Makel noch beheben könnte?
     

  7. #7
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Zitat Zitat von Orthak Beitrag anzeigen
    Zeile 52 macht mir noch etwas Sorgen. Doch ohne sie ist das letzte struct doppelt enthalten.
    Ja, das hatten wir doch schonmal...

    Warum verwendest du denn .eof()?

    \edit: Sorry, hab dich verwechselt. Aber zu dem Problem mit eof haben wir hier wirklich sehr viele Beiträge. Zuletzt in einem mit Roncalli.
    Zitat Zitat von Orthak Beitrag anzeigen
    In dieser Testanwendung habe ich allerdings auf strings in der struct verzichtet. Hat vielleicht Jemand einen Tip wie ich diesen Makel noch beheben könnte?
    Du müßtest die Daten serialisieren/deserialisieren. Die Strings könntest du z.B. serialisieren, indem du die Größe (als int) in die Datei schreibst, gefolgt von den Daten. Beim Auslesen liest du erstmal die Größe, so das du weißt wieviel Speicher du allokieren mußt. Dann kannst du den String direkt einlesen usw.

    Allerdings ist es da schöner (und portabler) die Struktur einfach in einem Textformat zu speichern. Das kann man mit einem Editor bearbeiten und die Struktur ist im Zweifelsfall einfacher zu ändern.

    Gruß
    Geändert von deepthroat (13.01.09 um 15:33 Uhr)
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  8. #8
    Orthak Orthak ist offline Mitglied Bronze
    Registriert seit
    Dec 2008
    Beiträge
    36
    Danke für den Tip bezüglich eof(). Ich habe die Funktion bisher auch immer sorglos in Schleifenbedingungen verwendet.

    Ich habe für mein Problem nun eine praktikable Lösung gefunden. Sie nimmt Vektoren mit den gewünschten structs auf, konvertiert und schreibt sie binär bzw. ließt und konvertiert zurück.

    Verwendete structs:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
        // QATuple Konstrukt
        typedef struct questionAnswersTuple {
            string question;
            string answer;
            string wrongAnswers[3];
        } QATuple;
     
        // QATuple Konstrukt (Binaeraustausch)
        typedef struct binaryTuple {
            char question[100];
            char answer[100];
            char wrongAnswer1[100];
            char wrongAnswer2[100];
            char wrongAnswer3[100];
        } BTuple;

    Die eigentlichen Funktionen:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    
    bool writeBinary(vector<QATuple>* paare, const char* fileName) {
     
        // Stream fuer binaeres Schreiben
        fstream binary_file(fileName, ios::out|ios::binary|ios::app);
     
        // Exception werfen bei Fehler
        if(!binary_file.is_open()) {
            string errorMsg = fileName;
            errorMsg += " konnte nicht geoeffnet werden!\n";
            throw (string)errorMsg;
        }
     
        for(unsigned int i = 0; i < paare->size(); i++) {
     
            BTuple tmp;
            sprintf(tmp.question, "%s", paare->at(i).question.c_str());
            sprintf(tmp.answer, "%s", paare->at(i).answer.c_str());
            sprintf(tmp.wrongAnswer1, "%s", paare->at(i).wrongAnswers[0].c_str());
            sprintf(tmp.wrongAnswer2, "%s", paare->at(i).wrongAnswers[1].c_str());
            sprintf(tmp.wrongAnswer3, "%s", paare->at(i).wrongAnswers[2].c_str());
     
            binary_file.write(reinterpret_cast<char*>(&tmp),sizeof(tmp));
        }
     
        binary_file.close();
        return true;
    }
     
    vector<QATuple> readBinary(const char* fileName) {
     
        BTuple tmpB;
        QATuple tmpS;
        vector<QATuple> paare;
     
        fstream binary_file(fileName, ios::binary|ios::in);
     
        // Exception werfen bei Fehler
        if(!binary_file.is_open()) {
            string errorMsg = fileName;
            errorMsg += " konnte nicht geoeffnet werden!\n";
            throw (string)errorMsg;
        }
     
        while(binary_file.read(reinterpret_cast<char*>(&tmpB),sizeof(tmpB))) {
            tmpS.question = tmpB.question;
            tmpS.answer = tmpB.answer;
            tmpS.wrongAnswers[0] = tmpB.wrongAnswer1;
            tmpS.wrongAnswers[1] = tmpB.wrongAnswer2;
            tmpS.wrongAnswers[2] = tmpB.wrongAnswer3;
            paare.push_back(tmpS);
        }
     
        binary_file.close();
        return paare;
    }
    Man muss natürlich aufpassen das die strings nicht über 100 Zeichen haben, bzw. dann die Austauschstruktur anpassen.

    Vielen Dank für die ganzen hilfreichen Antworten!
     

Ähnliche Themen

  1. C-structs und Vererbung?!
    Von canfänger im Forum C/C++
    Antworten: 12
    Letzter Beitrag: 02.02.10, 21:42
  2. Liste für 2 Structs
    Von Need_Name im Forum C/C++
    Antworten: 8
    Letzter Beitrag: 04.01.10, 14:49
  3. Protokollsachen: Structs aus C++ übernehmen?
    Von BeaTBoxX im Forum .NET Application und Service Design
    Antworten: 3
    Letzter Beitrag: 15.12.06, 13:39
  4. Anzahl Structs beschränkt?
    Von Lord_Istari im Forum C/C++
    Antworten: 5
    Letzter Beitrag: 17.04.04, 09:33
  5. [C] Warnung bei structs
    Von rookie im Forum C/C++
    Antworten: 3
    Letzter Beitrag: 10.02.03, 12:55