C++ komplette Struktur in Datei speichern und auslesen

$ch4pse

Lt. Junior Grade
Registriert
Feb. 2007
Beiträge
390
Hi Leute,

Folgendes Problem, ich programmier im Moment an son ner art Inventur-Software rum. Insgesamt gibts da 13 Eingabefelder(2x unsigned int und 11x String) die alle in einer Strktur stehn. Jetzt nöchte ich per buttonklick n speicherdialog aufrufen(soweit bin ich schon mit meinem Quelltext) und das ganze in eine Datei speichern. Insgesamt gibts in der Struktur jede Variable 20mal (im Prinzip also alles Felder). Das ganz soll dann in etwa so gespeichert werden, dass er zum Beispiel n zähler hochzählt und immer in ne neue Zeile der Datei die komplette struktur mit dem indizes von dem zähler schreibt. Auf diese Art und Weise isses dann nämlich einfacher die Datei auch nacher wieder zu laden und wieder in die struktur zu schreiben. Wie mach ich denn das?? Unten mal mein Quellcode für den speicher-Dialog soweit wie ich jetzt bin.


Code:
void __fastcall TForm1::Speichern1Click(TObject *Sender)
{
String verzeichnis;
SaveDialog1->Execute();
verzeichnis=SaveDialog1->FileName;
FILE* datei;
datei=fopen(verzeichnis.c_str(),"rb");
fread(data.c_str(),sizeof(data),1,datei);
fclose(datei);
}
 
Kann dir bei dem konkreten Problem jetzt nicht weiterhelfen, da ich eher Delphi-Programmierer bin. Aber einwas könntest du erheblich optimieren:

Das SaveDialog1->Execute würde ich als Bedingung in einer If-Struktur machen, und alle darauf bezogenen Arbeiten dann als Abhängigkeit ausführen, quasi

Code:
IF SaveDialog1->Execute() {
verzeichnis=SaveDialog1->FileName;
FILE* datei;
datei=fopen(verzeichnis.c_str(),"rb");
fread(data.c_str(),sizeof(data),1,datei);
fclose(datei);
.
.
.
}
Was dir das bringt? Das findest du ganz schnell raus, wenn du bei dem Speichern-Dialog mal statt auf "Speichern" auf "Abbrechen" drückst ;)
 
Hi,

wozu konkret brauchst du den Zähler denn?

Du kannst die einzelnen Stucts einfach direkt hintereinander in die Datei schreiben, du musst nichts zeilenweise machen, das interessiert nur, wenn es um Text geht.


Edit:
Ich würde auch damit anfagnen statt "rb" mal mit "wb" zu öffnen und statt fread mal fwrite zu machen...
 
Naja ich würde dafür eigentlich garkeine Text-Datei nehmen!
Willst du, wenn du mal 100000 Einträge hast, das ganze auch komplett einlesen?
Nimm doch eine Datenbank, MySQL oder SQLite

Gruß David.
 
Sow danke erstmal für eure Antworten.

@1668mib: Wenn das auch so funktioniert, dann is das ja super, aber eventuell könntest du mir auch verraten wie das geht??

@davidbaumann: hehe das is mir ersten im Moment noch zu stressig und zweitens werde dass sicher keine 100000 Einträge sonder maximal 20, denn mehr verschiedene Produkte werden nicht gelagert^^
 
Ja aber dann hast du eine Standardisierte Speicherung, und kannst viel mehr, ganz einfach damit machen.
Export, Auswertung, Ausgabe über eine Web-Oberfläche...
Ist meiner Meinung nach einfacher!
 
1.) Auf gar keinen Fall darf man Strukturen einfach so speichern mit dem sizeof Operator. Das Ergebnis von der Datei hängt da sehr stark vom Compiler bzw. seinen Einstellungen ab. Eine Optimierung des Compilers ist es nämlich die größe einer Struktur auf ein Vielfaches von 4Byte, 8Byte oder 16Byte aufzufüllen. Da der Compiler ja nicht weiß, dass du den sizeof Operator nicht für den RAM verwendest, sondern für die Datei, liefert der dann auch z.B. statt 13 Bytes 16 Bytes. Einmal abgesehen davon, ist es dir unmöglich deine Struktur durch diverse Felder zu erweitern.

Das Abspeichern von Daten hat so auszusehen, dass man für jede Struktur händisch eine Methode implementiert, mit der sie serialisiert bzw. deserialisiert werden kann. Sobald man mehr als nur natürliche Datentypen hat, sondern auch Pointer, Strings etc., dann kommt man da sowieso nicht herum. Weiters muss fix festgelegt werden, welche Daten in welcher Reihenfolge kommen z.B. zuerst der Vorname, dann der Nachname und dann das Geburtsdatum einer Person.

2.) Wenn man die Datei zu mehr als nur ein bisschen herumtesten nehmen will, dann sollte man sich auch eine ordentliche Codierung einfallen lassen, damit Daten nicht irrtümlich falsch interpretiert werden.
Ich benutze z.B. folgende Codierung über Messages sowohl für Netzwerk, als auch Dateioperationen:

Byte 0: Typ-Code für das Objekt, das ich speichern bzw. übers Netzwerk verschicken will. Die Codes sind auf beiden Seiten (Lese- und Schreibseite) fix vorgegeben.
Byte 1-4: Geben die Länge der Daten ein, die dann in einem Zug in den RAM gelesen werden können, was die Performance deutlich verbessert.
Byte 5-Ende

Falls Daten daher kommen, die einen nicht erwarteten Typ haben, dann breche ich die Kommunikation mit einer Fehlermeldung ab.

Falls man größere Datenblöcke hat, die nicht im RAM liegen (z.B. Dateien) kann man diese zwischen den Messages schachteln.

XML Strukturen wären noch etwas stabiler, aber bei der Interpretierung auch deutlich langsamer. Gerade übers Netzwerk könnten hier nur einzelne Bytes gelesen werden, da immer auf End Tags geprüft werden müsste, was die maximale Datenrate auf ca. 100KB/s begrenzt.
 
Ich wäre immernoch für die Verwendung einer Datenbank.
Was du machst, ist ja auch eine Datenbank.
Bis das ganze Fehlertolerant programmiert ist, hast du das Rad neu erfunden, ewig viel unüberschaubaren Code, und niemals die Performance von MySQL oder ähnlichen DBMS.
Du kannst sicher auch SQLite einbinden... das benötigt dann keine laufen Instanz von MySQL.
 
Zurück
Oben