ERLEDIGT
JA
JA
ANTWORTEN
7
7
ZUGRIFFE
506
506
EMPFEHLEN
-
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;
-
12.01.09 14:08 #2
- Registriert seit
- Jun 2005
- Beiträge
- 8.168
Hi.Du widersprichst dir irgendwie selbst. Wobei hast du denn nun Probleme?
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.
-
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:
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.Code :1 2 3
typdec struct a{ float *ptr; } A;
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
-
Stimmt, das klingt irgendwie unlogisch. Letzteres wäre das richtige Wort gewesen
.
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?lies die Daten in einen std::vector ein
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 ZeileBist du dir sicher, das das schrieben funktioniert?
liefert wie erhoft den geschriebenen Wert der ersten struct (siehe Ende von readBinary).Code :1
printf("Frage: %s\n", p_Data.question.c_str());
-
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.
-
Schade, das Program muss sich die Daten wirklich irgendwo aus dem Speicher geholt haben, denn nach einem Neustart funktioniert es tatsächlich nicht mehrHmm dann beende bitte mal dein Programm oder leer zwischendurch mal deinen Speicher
.
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:
Zeile 52 macht mir noch etwas Sorgen. Doch ohne sie ist das letzte struct doppelt enthalten.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; }
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?
-
13.01.09 15:24 #7
- Registriert seit
- Jun 2005
- Beiträge
- 8.168
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.
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.
-
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:
Man muss natürlich aufpassen das die strings nicht über 100 Zeichen haben, bzw. dann die Austauschstruktur anpassen.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; }
Vielen Dank für die ganzen hilfreichen Antworten!
Ähnliche Themen
-
C-structs und Vererbung?!
Von canfänger im Forum C/C++Antworten: 12Letzter Beitrag: 02.02.10, 21:42 -
Liste für 2 Structs
Von Need_Name im Forum C/C++Antworten: 8Letzter Beitrag: 04.01.10, 14:49 -
Protokollsachen: Structs aus C++ übernehmen?
Von BeaTBoxX im Forum .NET Application und Service DesignAntworten: 3Letzter Beitrag: 15.12.06, 13:39 -
Anzahl Structs beschränkt?
Von Lord_Istari im Forum C/C++Antworten: 5Letzter Beitrag: 17.04.04, 09:33 -
[C] Warnung bei structs
Von rookie im Forum C/C++Antworten: 3Letzter Beitrag: 10.02.03, 12:55





Zitieren

Login






