Binärdatei schreiben und lesen
-
Toller Fehler im Programm deines Profs: der Wert ist noch gar nicht in die Datei geschrieben, wenn er ausgelesen wird (weil Schreiben und Lesen gepuffert sind).
Entweder noch
schreiben.close();ausführen oder aber die gesamten "schreiben"-Zeilen in einen eigenen Block packen:
{ ofstream schreiben; schreiben.open("c:/ziel.txt", ios::out|ios::binary); if(!schreiben){ cerr << "Datei existiert nicht"; exit(-2); } schreiben.write((char*)&d,sizeof(d)); }(so wird der Destruktor automatisch ausgeführt, welcher dann die Datei schließt und die gepufferten Daten wegschreibt - Stichwort: RAII)
-
Cabooze schrieb:
Ich wusste bisher nicht, dass ein Destruktor oder ein Kopierkonstruktor mal ein Problem sein könnte.
Sie sind kein Problem. Das Problem ist, dass du auf einer Methode beharrst, die einfach nicht geht und die selbstdefinierten Konstruktoren und Destruktoren sind dabei nur ein kleiner Teil, warum das nicht geht. Und es ist ohnehin komisch, dass du sie selber definieren möchtest, denn:
Ich hatte das auch immer so verstanden, dass eine Klasse immer unbedingt einen Destruktor braucht.
Deswegen wird ja auch automatisch einer erzeugt, wenn du keinen eigenen angibst (ebenso bei einer ganzen Reihe anderer Memberfunktionen). Aber wenn du einen eigenen angibst, dann wird angenommen, dass du dir dabei was gedacht hast und da wichtiger Code drin steht. Deswegen spielt das eine Rolle, ob diese Funktionen existieren oder nicht, denn dann würde es keinen Sinn machen, sie einfach zu übergehen. Aber anscheinend hast du dir gar nichts gedacht, weswegen dies ein behebbares Hindernis ist.
std::string hat aber trotzdem immer noch nicht-triviale Konstruktoren (und die anderen speziellen Memberfunktionen sind ebenfalls nutzerdefiniert) und die machen auch wichtige Sachen. Weswegen man eben keinen std::string einfach so aus dem Nichts zaubern kann, indem man ein paar Bytes setzt, ohne diese Funktionen aufgerufen zu haben.
Aber wenn ich das jetzt richtig verstanden habe sind die bei Memberfunktionen schwachsinnig, ne?
Häh?
Und es funktioniert auch nicht...
Sind wir wieder am Anfang des Threads?SeppJ schrieb:
"Klappt nicht", "er meckert" und "ich bekomme eine Fehlermeldung" sind keine brauchbaren Problembeschreibungen.
Hätte ich noch ausdrücklich erwähnen müssen, dass "funktioniert nicht" ebenfalls keine brauchbare Fehlerbeschreibung ist? Leuten, die sich selber im Weg stehen, kann man einfach nicht helfen. (Aber vielleicht versuchst du mal, die gleiche Datei nicht mehrmals gleichzeitig zu öffnen)
-
Th69 schrieb:
Toller Fehler im Programm deines Profs: der Wert ist noch gar nicht in die Datei geschrieben, wenn er ausgelesen wird (weil Schreiben und Lesen gepuffert sind).
Entweder noch
schreiben.close();ausführen oder aber die gesamten "schreiben"-Zeilen in einen eigenen Block packen:
{ ofstream schreiben; schreiben.open("c:/ziel.txt", ios::out|ios::binary); if(!schreiben){ cerr << "Datei existiert nicht"; exit(-2); } schreiben.write((char*)&d,sizeof(d)); }(so wird der Destruktor automatisch ausgeführt, welcher dann die Datei schließt und die gepufferten Daten wegschreibt - Stichwort: RAII)
Oh sorry. Nein das ist mein Fehler. Das close hab ich vergessen.
Ok das war der Fehler. Dieses Programm funktioniert nun immerhin.
-
SeppJ schrieb:
Cabooze schrieb:
Ich wusste bisher nicht, dass ein Destruktor oder ein Kopierkonstruktor mal ein Problem sein könnte.
Sie sind kein Problem. Das Problem ist, dass du auf einer Methode beharrst, die einfach nicht geht und die selbstdefinierten Konstruktoren und Destruktoren sind dabei nur ein kleiner Teil, warum das nicht geht. Und es ist ohnehin komisch, dass du sie selber definieren möchtest, denn:
Ich hatte das auch immer so verstanden, dass eine Klasse immer unbedingt einen Destruktor braucht.
Deswegen wird ja auch automatisch einer erzeugt, wenn du keinen eigenen angibst (ebenso bei einer ganzen Reihe anderer Memberfunktionen). Aber wenn du einen eigenen angibst, dann wird angenommen, dass du dir dabei was gedacht hast und da wichtiger Code drin steht. Deswegen spielt das eine Rolle, ob diese Funktionen existieren oder nicht, denn dann würde es keinen Sinn machen, sie einfach zu übergehen. Aber anscheinend hast du dir gar nichts gedacht, weswegen dies ein behebbares Hindernis ist.
std::string hat aber trotzdem immer noch nicht-triviale Konstruktoren (und die anderen speziellen Memberfunktionen sind ebenfalls nutzerdefiniert) und die machen auch wichtige Sachen. Weswegen man eben keinen std::string einfach so aus dem Nichts zaubern kann, indem man ein paar Bytes setzt, ohne diese Funktionen aufgerufen zu haben.
Aber wenn ich das jetzt richtig verstanden habe sind die bei Memberfunktionen schwachsinnig, ne?
Häh?
Und es funktioniert auch nicht...
Sind wir wieder am Anfang des Threads?SeppJ schrieb:
"Klappt nicht", "er meckert" und "ich bekomme eine Fehlermeldung" sind keine brauchbaren Problembeschreibungen.
Hätte ich noch ausdrücklich erwähnen müssen, dass "funktioniert nicht" ebenfalls keine brauchbare Fehlerbeschreibung ist? Leuten, die sich selber im Weg stehen, kann man einfach nicht helfen. (Aber vielleicht versuchst du mal, die gleiche Datei nicht mehrmals gleichzeitig zu öffnen)
Also die Konstruktoren und Destruktoren sind ja nicht benutzerdefiniert (nicht mehr) und den Virtuellen kopierkonstruktor hab ich raus. Also sollte das dann(außer die string attribute) funktionieren?
Und da man wie du sagst keine Strings einfach in eine Datei lesen und schreiben kann, wären doch dann nur c-strings die möglicihkeit oder?
-
Cabooze schrieb:
Und da man wie du sagst keine Strings einfach in eine Datei lesen und schreiben kann, wären doch dann nur c-strings die möglicihkeit oder?
Kommt drauf an, was du unter "einfach" und "C-Strings" genau verstehst. Ein C-String ist nur eine Konvention, wie man in C das Ende einer Zeichenkette markiert, die unterliegende Datenstruktur (die ist es, auf die es ankäme, wenn du wirklich ganz naiv read/write benutzen willst) ist nicht genauer spezifiziert.
-
@Cabooze: Unter Disch's tutorial to good binary files gibt es einen Überblick über das Schreiben von Binärdateien. Unter "2) Define your complex types" werden anhand vom std::string-Datentyp drei verschiedene Optionen vorgestellt (wobei m.E. der 3. der beste Weg ist, also erst die Länge und dann den (evtl. noch nullterminierten) String wegschreiben).
-
Tut mir leid, ich krieg es immernoch nicht gebacken mit Strings.
string d = "einstring"; string b; int size = d.size(); ofstream schreiben; schreiben.open("/cygdrive/c/bla.dat", ios::out|ios::binary); if(!schreiben){ cerr << "Datei existiert nicht"; exit(-2); } schreiben.write((char*)&size , sizeof(int)); schreiben.write(d.c_str() , d.size()); schreiben.close(); ifstream lesen; lesen.open("/cygdrive/c/bla.dat", ios::in|ios::binary); cout << "6"; if(!lesen){ cerr << "Datei existiert nicht"; exit(-3); } lesen.read((char*)&size , sizeof(int)); lesen.read((char*)&b, d.size()); lesen >> b; lesen.close(); cout << b;Da ist immernoch irgendwas falsch. Das Programm bricht immernoch mit Run failed ab, bevor er überhaupt den Code liest.
-
Was jedenfalls in's Auge springt ist, dass Du
d.c_str()wegschreibst und in&bliest. Was macht denn Zeile 34 eigentlich?
-
Furble Wurble schrieb:
Was jedenfalls in's Auge springt ist, dass Du
d.c_str()wegschreibst und in&bliest. Was macht denn Zeile 34 eigentlich?Ja Zeile 34 war so n test. Hätt ich vielleicht noch wegmachen sollen. Und &b wollte ich absichtlich lesen.
Naja ich hab es jetzt anders gemacht. Das auslesen sieht bei mir nun so aus:ifstream lesen; lesen.open("/cygdrive/c/bla.txt", ios::in|ios::binary); if(!lesen){ cerr << "Datei existiert nicht"; exit(-3); } lesen.read((char*)&size2,sizeof(int)); // größe wird zuerst ausgelesen damit sie bekannt ist char wort[size2]; lesen.read(wort, size2); for(int i = 0; i< size2; i++){ b += wort[i]; }Und endlich funktioniert es!
Den Code zum einlesen hab ich gelassen. MIch wundert nur eins: Die Daten die "Binär" auf die Datei geschrieben sind, sind trotzdem lesbar. Müssten da nicht irgendwelche kryptischen zeichen stehen oder ist das normal?
-
Hmm, da war ich wohl etwas sparsam...
Du kannst direkt in den String lesen. Nur musst Du Deine Daten halt dahin schreiben, wo der String seine Daten hält. Und dieser Puffer muss auch groß genug sein:
lesen.read((char*)&size , sizeof(int)); b.resize(size); // Platz schaffen lesen.read(&b[0], size); // Du siehst den Unterschied zu Deinem Code.
-
Das mit den Binärdaten ist normal.
ios::binarybedeutet einfach, dass Zeilenumbrüche nicht konvertiert werden sollen. Der eigentliche Unterschied zwischen binär und formatiert liegt in der Ausgabemethode.ofstream::writeschreibt die Daten so wie sie sind raus, im Falle von strings ASCII/UTF8, je nach Zeichensatz oder beiints eben die 4/8 Bytes. Der<<-Operator schreibtstringauch als ASCII/UTF8 raus,ints allerdings auch in lesbarer Form alsstring.