Struct in Datei schreiben und Werte nachträglich ändern. Lösung.
-
madking75 schrieb:
PuppetMaster2k schrieb:
Oha. Das erste was mir hier in die Augen springt sind die globalen Variablen. Die sollte man soweit es geht vermeiden. Das Zweite was mit aufgefallen ist, du nutzt C und C++. Eine nicht wirklich schöne Mischung. Entweder C oder C++!
Für ein kurzes kleines Beispielprogramm hast du aber hohe Erwartungen.
Ich würde es nicht gerade hohe Erwartung nennen, wenn er verlangt das du in der Sprache schreibst, für die du die Lösung vorschlägst
madking75 schrieb:
PuppetMaster2k schrieb:
Warum istream und ostream? ifstream, ofstream und fstream sind speziell für Dateihandling gedacht.
Damit man die Datei nicht zweimal öffnen muss! Und für was sind denn deiner Meinung nach istream und ostream "speziell" gedacht? Für Dumm in Bibliotheken rumgammeln?
Sie sind also unspezialisierte Ströhme gedacht. Mal abgesehen davon das sie typedefs sind kannst du sie überall hin richten. Die fstreams sind extra für Dateiarbeit gedacht, und bringen gewiss einige Vorteile mit sich auf dem Gebiet. Aber trotz der mich nervenden Tatsache, dass die Trennung aber nicht durchgezogen wird, bin ich nicht der Meinung das man die fstreams abschaffen sollte.
madking75 schrieb:
PuppetMaster2k schrieb:
Zur Prüfung auf eof() solltest du dir mal fogendes durchlesen: http://fara.cs.uni-potsdam.de/~kaufmann/?page=GenCppFaqs&faq=eof#Answ
Und was bringt mir das?
Hast du den Text überhaupt gelesen?
madking75 schrieb:
PuppetMaster2k schrieb:
Von wegen Datei muss existieren, wenn du if/of/fstream nutzt und eine Datei nicht existiert, wird dies automatisch erzeugt. Allerdings sollte man hier prüfen ob weder das öffnen noch das erstellen (falls Datei nicht vorhanden) nicht fehlgeschlagen sind.
Was soll dieses Programm denn mit einer leeren Datei anfangen?
Das ist ein Berechtigter Einwand.
madking75 schrieb:
PuppetMaster2k schrieb:
Vielleicht solltest du dein Programm dahingehend noch mal ändern, bevor du das eine Lösung nennst.
Okay, ich werde das nächstemal 10.000 Quellcodes reinposten, wo nur jede erdenkliche Situation behandelt wird.
Du brauchst nicht so zu reagieren, bloß weil er dir einen Hinweis gibt. Niemand erwartet von dir, dass du 10000 Quellcodes postest. Aber wenn du eine Lösung anbietest, sollte sie schon mal mindestens 2 Dinge tun:
In c++ geschrieben sein (keine Mischung mit c)
und die Standard c++ Bibliothek benutzen und so benutzen, wie es gedacht war, es sei denn, du möchtest die Implementation erklären.madking75 schrieb:
Ich würd sagen: Setzen, Sechs!
Genau. Für dich.
-
Hab mir die eof seite angeschaut, ist wirklich gut. Danke.
-
Okay sorry, ich dacht ja meinen Quellcode mehr als Denkanstoß. Aber durch eure guten Postings habe ich mein Ziel ja erreicht.
Ich versuch den Code anzupassen bzw. umzuschreiben und post ihn nochmal hier rein.
-
madking75 schrieb:
Okay sorry, ich dacht ja meinen Quellcode mehr als Denkanstoß.
Und das ist auch eine gute Idee, da, wie du ja selbst festgestellt hast, manche (viele?) Leute Probleme damit haben. Mein post wurde eigentlich nur durch deine erste Antwort ausgelöst.
-
Auch wenn die Sache schon geklärt ist, geb ich dennoch kurz meine Meinung zum Besten.
Ich hatte keine besonders hohen Ansprüche gestellt. Da ich davon ausgegangen bin, wenn hier jemand eine Lösung präsentiert, dann wird sie auch vollständig (und effizient) sein. Aber für eine Lösung war das eben einfach nicht ausreichend. Und das habe ich weiter oben eben nur ausführlicher ausgedrückt. War vielleicht ein bischen barsch ausgedrückt, war aber keine Absicht.
Aber die Sache ist ja jetzt klar. Mal sehen wie deine nächste Lösung aussihet
-
Genau. Setz dich nochmal ran, verbessere das was gesagt wurde und zeige das Ergebnis hier. Dann hast du gleich mehrere Dinge erreicht:
- selber was dazugelernt
- anderen geholfen
- und einen vielleicht faq-reifen Beitrag erstellt
-
Ich habe nur eine bescheidene Bitte.
Wenn du den Code nochmal postest oder du ihn aus deinem ersten Post bearbeitest, setze den Code doch bitte in [ cpp ][/ cpp ] (ohne Leerzeichen) Tags.Ich finde das erhöht die Lesbarkeit erheblich.
Caipi
-
Argh!
Ich hab den Quellcode hier wieder rausgenommen, hab nen krassen Fehler gefunden. Das mit dem c/c++ tag ist mir richtig Peinlich
Allen frohe Weihnachten! :xmas2:
-
EDIT: Funktionen angepaßt.
So, ich hoffe der ganze Code ist jetzt in C++. Ich hab versucht den kompletten Dateizugriff mit einer Klasse zu lösen, aber da entstand der totale Gau. Habs aufgegeben und will das Problem mit zwei Funktionen lösen.
In den Funktionen wird direkt nach dem Lesen mit der Memberfunktion good() der Dateistream ausgewertet und ggf. durch "return false;" die while-Schleife beendet. Da die while-Schleife sofort beendet wird, verarbeite ich nicht mehr den Datenschrott.
Ich finde das es eine sehr gute Lösung ist. Aber leide bekomme ich einen Speicherzugriffsfehler wenn ich das Programm ausführe. Der Fehler kommt bevor nach main() was ausgeführt wird, hab dort Testhalber ein cout << "test" eingefügt.Ich hab noch eine Frage: Bei einer Datei, die ich zum lesen und schreiben öffne, sind da seekp und seekg unabhängig voneinander?
#include <iostream> #include <fstream> #include <string> #include <sstream> using namespace std; bool fileread(istream& is, char* s, streamsize n) // Binär lesen { is.read(s,n); if(is.good()) return true; return false; } bool filegetline(istream& is, char* s, streamsize n, char delim = '\n') // Ascii lesen { is.getline(s,n,delim); if(is.good()) return true; return false; } int main() { ifstream datei_lesen; // <- In diesem Beispiel eine Textdatei, nur diese eine Datei muss ofstream datei_ergebnis; // vorhanden sein, sonst funktioniert dieses Beispielprogramm nicht. Siehe unten für weitere Infos. fstream datei_wahlfrei; int zeile=5; // "Da wo" der Wert geändert werden soll int zeilen=0; // Zählt die gelesenen Zeilen int neuwert=99; // Der neue Wert struct strdaten // die Daten { int x1; int x2; int x3; } daten; unsigned long strdatensize=sizeof(strdaten); // Tuning, bemerkbar nur bei sehr großen Dateien. ///// Datenstätze in Binär umwandeln string text; // Benötigt um die Ascii Datei an daten zu übergeben stringstream temp; // int pos; // int postmp=0; // datei_lesen.open("daten.txt",ios_base::in); if(!datei_lesen.is_open()) exit(1); datei_wahlfrei.open("binaer.bin",ios_base::in|ios_base::out|ios_base::binary|ios_base::trunc); if (!datei_wahlfrei.is_open()) exit(2); while (filegetline(datei_lesen,(char *) &text,10)) { temp << text.substr(postmp,(pos=text.find(";",postmp))-1); temp >> daten.x1; postmp=pos+1; temp << text.substr(postmp,(pos=text.find(";",postmp))-1); temp >> daten.x2; postmp=pos+1; temp << text.substr(postmp,(pos=text.find(";",postmp))-1); temp >> daten.x3; postmp=0; datei_wahlfrei.write((char *) &daten, strdatensize); zeilen+=1; } //datei_lesen.clear(); // Nur zur Info, wenn die Datei //datei_lesen.seekg(0,ios_base::beg); // weiter benutzt werden soll datei_lesen.close(); ///// In zeile Wert von x1 ändern if(zeile>zeilen) exit(4); // Zur Sicherheit datei_wahlfrei.seekg(zeile*strdatensize,ios_base::beg); datei_wahlfrei.read((char *) &daten, strdatensize); daten.x1=neuwert; datei_wahlfrei.seekp(-strdatensize,ios_base::cur); datei_wahlfrei.write((char *) &daten, strdatensize); datei_wahlfrei.seekg(0,ios_base::beg); datei_wahlfrei.seekp(0,ios_base::beg); // Sinnvoll nach seekg? ///// Datensätze in Ascii umwandeln datei_ergebnis.open("ergebnis.txt",ios_base::out|ios_base::trunc); if(!datei_ergebnis.is_open()) exit(3); datei_wahlfrei.seekg(0,ios_base::beg); while (fileread(datei_wahlfrei,(char *) &daten,strdatensize)) { datei_ergebnis << daten.x1 << ";" << daten.x2 << ";" << daten.x3 << "\n"; } //datei_wahlfrei.clear(); // Nur zur Info, wenn die Datei //datei_wahlfrei.seekg(0,ios_base::beg); // weiter benutzt werden soll datei_wahlfrei.close(); datei_ergebnis.close(); return 0; } // Die Datei daten.txt muss folgendermaßen aufgebaut sein: // // z.B.: // 12;4;0 // 99;1;99 // Drei ganzzahlen, getrennt mit Semikollon // Jede Zeile muss mit einem Return abgeschlossen sein. // Sie können natürlich das Format von ihrer Datei im Quelltext anpassen.
-
Ist der Code wirklich so schlecht, oder warum bekomme ich keine Antwort?
Wäre das vielleicht besser: Eine Kopie der Klasse fstream erstellen und filegetline und fileread dort einfügen?
-
Ich hab jetzt was gefunden:
string text; Erzeugt innerhalb der while-Schleife für einen Speicherzugriffsfehler.
Mit char text[10]; Bleibt der Fehler aus, die Daten in text[10] sind in Ordnung. Nur möchte ich strings verwenden und keinen char [], sonst müßt ich ja wieder c-Routinen verwenden. Das Programm soll aber komplett in C++ sein.
Ich hab mir jetzt schon überlegt einen Zeiger auf dem String zu übergeben. Mal schaun.
Falls einer es nicht bemerkt hat, ich habe die fehlerhaften Funktionen bereits ausgetauscht.
-
ENDLICH !!! Mein Gott diese Fehler! DIESE FEHLER !!! Ich bin in C++ ganz schön eingerostet. Bestimmt geht vieles Einfacher als ich Denke. Jedenfalls funktioniert der Code jetzt Tadellos. Ich mach drei Kreuze!
Code ohne Remarks:
#include <fstream> using namespace std; bool fileread(istream& is, char* s, streamsize n); bool filegetline(istream& is, string& s, char delim = '\n'); int main() { ifstream datei_lesen; ofstream datei_ergebnis; fstream datei_wahlfrei; int zeile=5; int zeilen=0; int neuwert=99; struct strdaten { int x1; int x2; int x3; } daten; unsigned long strdatensize=sizeof(strdaten); string gettext; string gettemp; int position; int position2; int anzahl; ///// Datenstätze in Binär umwandeln datei_lesen.open("daten.txt",ios_base::in); if(!datei_lesen.is_open()) exit(1); datei_wahlfrei.open("binaer.bin",ios_base::in|ios_base::out|ios_base::binary|ios_base::trunc); if (!datei_wahlfrei.is_open()) exit(2); while (filegetline(datei_lesen,gettext)) { position=gettext.find(";",0); anzahl=position; gettemp = gettext.substr(0,anzahl); daten.x1 = atoi(gettemp.c_str()); position++; position2=gettext.find(";",position); anzahl=position2-position; gettemp = gettext.substr(position,anzahl); daten.x2 = atoi(gettemp.c_str()); position=position2+1; position2=gettext.find("\n",position); anzahl=position2-position; gettemp = gettext.substr(position,anzahl); daten.x3 = atoi(gettemp.c_str()); datei_wahlfrei.write((char *) &daten, strdatensize); zeilen+=1; } datei_lesen.close(); ///// In zeile Wert von x1 ändern if(zeile>zeilen) exit(4); datei_wahlfrei.seekg(zeile*strdatensize,ios_base::beg); datei_wahlfrei.read((char *) &daten, strdatensize); daten.x1=neuwert; datei_wahlfrei.seekp(-strdatensize,ios_base::cur); datei_wahlfrei.write((char *) &daten, strdatensize); datei_wahlfrei.seekg(0,ios_base::beg); ///// Datensätze in Ascii umwandeln datei_ergebnis.open("ergebnis.txt",ios_base::out|ios_base::trunc); if(!datei_ergebnis.is_open()) exit(3); while (fileread(datei_wahlfrei,(char *) &daten,strdatensize)) { datei_ergebnis << daten.x1 << ";" << daten.x2 << ";" << daten.x3 << "\n"; } datei_wahlfrei.close(); datei_ergebnis.close(); return 0; } bool fileread(istream& is, char* s, streamsize n) { is.read(s,n); if(is.good()) return true; is.clear(); return false; } bool filegetline(istream& is, string& s, char delim) { getline(is,s,delim); if(is.good()) return true; is.clear(); return false; } // Die Datei daten.txt muss folgendermaßen aufgebaut sein: // // z.B.: // 12;4;0 // 99;1;99 // Drei ganzzahlen, getrennt mit Semikollon // Jede Zeile muss mit einem Return abgeschlossen sein. // Sie können natürlich das Format von ihrer Datei im Quelltext anpassen.
Code mit Remarks:
//#include <iostream> #include <fstream> //#include <string> //#include <sstream> //#include <istream> //#include <cstdlib> using namespace std; bool fileread(istream& is, char* s, streamsize n); // Binär lesen bool filegetline(istream& is, string& s, char delim = '\n'); // Ascii lesen int main() { ifstream datei_lesen; // <- In diesem Beispiel eine Textdatei, nur diese eine Datei muss ofstream datei_ergebnis; // vorhanden sein, sonst funktioniert dieses Beispielprogramm nicht. Siehe unten für weitere Infos. fstream datei_wahlfrei; int zeile=5; // "Da wo" der Wert geändert werden soll int zeilen=0; // Zählt die gelesenen Zeilen int neuwert=99; // Der neue Wert struct strdaten // die Daten { int x1; int x2; int x3; } daten; // Tuning, bemerkbar nur bei sehr großen Dateien. unsigned long strdatensize=sizeof(strdaten); // Speicher die Größe von strdaten, wird zum Binären Schreiben und Lesen benötigt // Benötigt um die Ascii Datei an daten zu übergeben string gettext; // Enthält eine komplette Zeile von daten.txt string gettemp; // Enthält den gewünschten Bereich einer Zeile int position; // Speichert die Position int position2; // Speichert die Position int anzahl; // Speichert die Anzahl der Stellen der Zahl ///// Datenstätze in Binär umwandeln datei_lesen.open("daten.txt",ios_base::in); // Datei daten.txt zum lesen öffnen. if(!datei_lesen.is_open()) exit(1); // Programm beenden, wenn die Datei nicht offen ist. datei_wahlfrei.open("binaer.bin",ios_base::in|ios_base::out|ios_base::binary|ios_base::trunc); // Datei binaer.txt zum lesen und schreiben im binär Modus öffnen. Existierende Datei wird gelöscht und neu angelegt. Nicht existierentende Datei wird neu angelegt. if (!datei_wahlfrei.is_open()) exit(2); // Programm beenden, wenn die Datei nicht offen ist. while (filegetline(datei_lesen,gettext)) // Schleife wird so oft wiederholt, bis Dateiende erreicht. { // Daten ins gewünschte Format umwandeln und daten.x1-x3 übergeben position=gettext.find(";",0); // Finde das erste Vorkommen von ";" anzahl=position; // Ergebnis ist die Anzahl der Stellen der ersten Zahl gettemp = gettext.substr(0,anzahl); // Kopiere den gewünschten Berich in den String daten.x1 = atoi(gettemp.c_str()); // Wandle den String als int um und übergebe ihn x1 von daten position++; // Position nach ersten ";" setzen position2=gettext.find(";",position); // Finde das erste Vorkommen von ";" ab position anzahl=position2-position; // Ergebnis ist die Anzahl der Stellen der zweiten Zahl gettemp = gettext.substr(position,anzahl); // daten.x2 = atoi(gettemp.c_str()); // position=position2+1; // Position nach zweiten ";" setzen position2=gettext.find("\n",position); // Finde das erste Vorkommen von "\n" ab position anzahl=position2-position; // Ergebnis ist die Anzahl der Stellen der dritten Zahl gettemp = gettext.substr(position,anzahl); // daten.x3 = atoi(gettemp.c_str()); // // Ende der Umwandlung für eine Zeile datei_wahlfrei.write((char *) &daten, strdatensize); // Eine Zeile daten binär in Datei binaer.txt Speichern zeilen+=1; // Zählt Anzahl der Zeilen } //datei_lesen.clear(); // Nur zur Info, wenn die Datei //datei_lesen.seekg(0,ios_base::beg); // weiter benutzt werden soll datei_lesen.close(); // Datei daten.txt schliessen ///// In zeile Wert von x1 ändern // Zur Sicherheit if(zeile>zeilen) exit(4); // Programm wird beendet, wenn die Zeile nicht existiert datei_wahlfrei.seekg(zeile*strdatensize,ios_base::beg); // Gehe zur gewünschten Zeile zum Lesen vom Anfang aus datei_wahlfrei.read((char *) &daten, strdatensize); // Lese gewünschte Zeile aus und speicher in daten daten.x1=neuwert; // Gib daten.x1 einen anderen Wert datei_wahlfrei.seekp(-strdatensize,ios_base::cur); // Gehe eine Zeile zurück zum Schreiben datei_wahlfrei.write((char *) &daten, strdatensize); // Überschreibe die Zeile mit dem neuen daten datei_wahlfrei.seekg(0,ios_base::beg); // Springe zum Anfang, egal ob mit seekg oder seekp ///// Datensätze in Ascii umwandeln datei_ergebnis.open("ergebnis.txt",ios_base::out|ios_base::trunc); // Öffne Datei ergebnis.txt zum Schreiben. Nicht existierende werden neu angelegt, existierende überschrieben. if(!datei_ergebnis.is_open()) exit(3); // Wenn ergebnis.txt nicht offen, Programm beenden while (fileread(datei_wahlfrei,(char *) &daten,strdatensize)) // Lese Zeile für Zeile bis zum Ende { datei_ergebnis << daten.x1 << ";" << daten.x2 << ";" << daten.x3 << "\n"; // Schreibe daten in ergebnis.txt } //datei_wahlfrei.clear(); // Nur zur Info, wenn die Datei //datei_wahlfrei.seekg(0,ios_base::beg); // weiter benutzt werden soll datei_wahlfrei.close(); // Schliesse binaer.txt datei_ergebnis.close(); // Schliesse ergebnis.txt return 0; // Programm Ende } bool fileread(istream& is, char* s, streamsize n) // Binär lesen { is.read(s,n); if(is.good()) return true; // Wenn der Datenstrom in Ordnung ist wird ein true zurückgegeben is.clear(); // Fehlerhaften Datenstrom zurücksetzen return false; } bool filegetline(istream& is, string& s, char delim) // Ascii lesen { getline(is,s,delim); if(is.good()) return true; // Wenn der Datenstrom in Ordnung ist wird ein true zurückgegeben is.clear(); // Fehlerhaften Datenstrom zurücksetzen return false; } // Die Datei daten.txt muss folgendermaßen aufgebaut sein: // // z.B.: // 12;4;0 // 99;1;99 // Drei ganzzahlen, getrennt mit Semikollon // Jede Zeile muss mit einem Return abgeschlossen sein. // Sie können natürlich das Format von ihrer Datei im Quelltext anpassen.
Die daten.txt:
13;41;3 23;12;16 12;32;30 49;3;18 34;12;14 24;36;23 30;13;36 44;23;4 31;44;6 49;5;39