Struct in Datei schreiben aus CodeGuru.com
-
Ja. Den Fehlerzustand überprüfen musst du ja auch.
Ja, und zwar in beiden Fällen (ich hoffe, du überprüfst den Fehlerzustand des Streams bevor du mit der Länge zu arbeiten anfängst?). Bei deinem Scheiß muss ich zusätzlich die Länge überprüfen bevor ich zu einem
size_t
konvertiere, und das ist redundant und nervig.Weil es so schwer zu verstehen ist dass mein Dateiformat explizit so große strings erlaubt?
Es erlaubt gar nichts.
size_t
(std::allocator<>::size_type
) auf der Leseplatform muss 8 Byte groß sein, sonst kannste einen solchen String nicht in einem Stück extrahieren und speichern, weder mitstring
noch mitnew[]
.Konsistenz.
Seit wann kompensiert deine heißgeliebte "Konsistenz" den anderen Ballast!?
Es ist konsistent, die Länge auch binär zu serialisieren? Sollen vielleicht Gürtel aus demselben Stoff wie Hosen gemacht werden, weil das konsistent zu den Hosen ist? inb4 not comparableWarum sollte binäres Schreiben von Integern nicht portabel lösbar sein?
Es ist portabel lösbar, wenn man die Endianness berücksichtigt. Vorteile? Keine signifikanten.
Aber sie haben die Länge nicht und müssen die Verarbeitung daher abbrechen statt genau sagen zu können was das Problem ist
Falsch.
size_t
wird aufstd::numeric_limits<size_t>::max()
gesetzt wenn die Länge zu groß ist. Die genaue Länge brauchen wir eh nicht, das Programm wird nicht weiter arbeiten können wenn die Daten nicht vollständig eingelesen werden können. Hätten wir Strings nutzen wollen/sollen die kleiner als 4GiB groß sind hätten wir sie auch so serialisiert.und die Verarbeitung danach weiterführen, wenn ich das will.
Was du natürlich niemals tun würdest, diese Möglichkeit existiert nur um sie hier als zusätzliche Option erwähnen zu können. Und falls wir das wollen würden, also den String separat in mehrere einzulesen falls die Länge zu groß ist, könnten wir immer noch im Stream zurückgehen und die Länge in einen
uint64_t
einlesen. Den entsprechenden Code leiten wir mit__builtin_unreachable
ein., dann kannst du nicht sicherstellen dass sie eingelesen werden können
Nein, aber wie wir bereits mehrfach erklärt habe... ach, lassen wirs.
Wenn du das als Nachteil anführst musst du als Gegenargument aber auch die bessere Performance akzeptieren.
Das hier ist kein Spiel nach Punkten. Die zwei Millisekunden die wir "langsamer sind" um dafür sauberen, lesbaren und portablen Code zu haben gönnen wir uns.
-
SeppJ schrieb:
Zwei Fehler:
-Vorteile formatierter IO ist nicht nur Menschenlesbarkeit. Ein Hauptvorteil ist Portabilität.Wie schon gesagt, ich sehe absolut nicht, wo man hier weniger Portabilitaet mit binaerer IO hat. Man muss sich bei beidem auf ein Format einigen. Bei formatierter IO gibt es Dinge wie Encoding, bei binaerer IO eben die Groesse der Typen. Endianess ist kein Problem, man kann Integer Endianess-unabhaengig lesen und schreiben ohne irgendwelche ifs.
SeppJ schrieb:
-Ich habe keine Ahnung, wieso du hier Zeichen escapen willst beim String. Es geht schon um binäre Speicherung des Strings. Es geht darum wie du die Länge mitbekommst. Da gibt es eben zwei Methoden, eine unportabel (und meinetwegen 3 µs schneller) und eine portabel.
Warum willst du ein lesbares File, aber einen binaeren String? Wenn da in dem File steht
14|k3?9 ??} ke?9?
dann ist das absolut nicht lesbar. (Ersetze '?' durch ein nicht druckbares Zeichen deiner Wahl)
Hat man hingegen"k3\x009\n\x01\x02}\nke\x039\x04"
dann ist das sehr schoen lesbar. Und mit Editieren fange ich garnicht erst an.
-
Arcoth schrieb:
Ja, und zwar in beiden Fällen (ich hoffe, du überprüfst den Fehlerzustand des Streams bevor du mit der Länge zu arbeiten anfängst?). Bei deinem Scheiß muss ich zusätzlich die Länge überprüfen bevor ich zu einem
size_t
konvertiere, und das ist redundant und nervig.Ja, so eine zusätzliche Bedingung in nem if ist schon extrem schwer...
Arcoth schrieb:
Es erlaubt gar nichts.
size_t
(std::allocator<>::size_type
) auf der Leseplatform muss 8 Byte groß sein, sonst kannste einen solchen String nicht in einem Stück extrahieren und speichern, weder mitstring
noch mitnew[]
.Darum gehts doch gar nicht.
Du musst unterscheiden zwischen dem Dateiformat und dem Program.Arcoth schrieb:
Konsistenz.
Seit wann kompensiert deine heißgeliebte "Konsistenz" den anderen Ballast!?
Es ist konsistent, die Länge auch binär zu serialisieren? Sollen vielleicht Gürtel aus demselben Stoff wie Hosen gemacht werden, weil das konsistent zu den Hosen ist? inb4 not comparableWenn du schon Vergleiche willst dann bitte wenigsten einen der Sinn macht. Was spricht gegen binär ? Außer dass man einmal etwas mehr Code hat. Dank Abstraktion wird man dem nie wieder begegnen.
Letztlich sieht der Code hinter den stream Routinen die dir die Zahlen in Text umwandeln nicht schöner aus. Oder ist dieser Code auch super unsauber und unportabel ?Arcoth schrieb:
Warum sollte binäres Schreiben von Integern nicht portabel lösbar sein?
Es ist portabel lösbar, wenn man die Endianness berücksichtigt. Vorteile? Keine signifikanten.
Es ging darum, dass "Portabilität" für formatted IO nur ein Pseudoargument ist.
Arcoth schrieb:
Aber sie haben die Länge nicht und müssen die Verarbeitung daher abbrechen statt genau sagen zu können was das Problem ist
Falsch.
size_t
wird aufstd::numeric_limits<size_t>::max()
gesetzt wenn die Länge zu groß ist. Die genaue Länge brauchen wir eh nicht, das Programm wird nicht weiter arbeiten können wenn die Daten nicht vollständig eingelesen werden können.Nur wenn dein Programm total Fehlerintolerant ist. Man kann den zu großen string überspringen und weiterarbeiten. Allerdings nur wenn man die exakte Länge kennt!
Arcoth schrieb:
Hätten wir Strings nutzen wollen/sollen die kleiner als 4GiB groß sind hätten wir sie auch so serialisiert.
Bitte was ?
Arcoth schrieb:
und die Verarbeitung danach weiterführen, wenn ich das will.
Was du natürlich niemals tun würdest, diese Möglichkeit existiert nur um sie hier als zusätzliche Option erwähnen zu können. Und falls wir das wollen würden, also den String separat in mehrere einzulesen falls die Länge zu groß ist, könnten wir immer noch im Stream zurückgehen und die Länge in einen
uint64_t
einlesen. Den entsprechenden Code leiten wir mit__builtin_unreachable
ein.Das ist wie mit strings größer als 4GB, braucht man eigentlich nicht, kann man sich aber offen halten. Vorallem dann wenn es keine Nachteile gibt. Außer natürlich der schrecklich unsauberen weiteren Bedingung.
Arcoth schrieb:
Wenn du das als Nachteil anführst musst du als Gegenargument aber auch die bessere Performance akzeptieren.
Das hier ist kein Spiel nach Punkten. Die zwei Millisekunden die wir "langsamer sind" um dafür sauberen, lesbaren und portablen Code zu haben gönnen wir uns.
Es ging darum, dass "Portabilität" für formatted IO nur ein Pseudoargument ist.
-
Hey Leute , bleibt mal aufn Teppich.
Ich wollt nur wissen wie ich´s am besten machen soll.Und ausser Kellerautomat und DarkShadwo hat sich keiner für mich besonders nützlich zu Wort gemeldet.
Also würd ich vorschlagen veröffentlicht doch dann eure Lösungen, oder macht den Thread zu.
-
Noch eine Frage zum code auf der ersten Seite.:
Habe jetzt beide Varianten gefunden, static_cast und reinterpret_cast.
Welches ist für diesen Fall vorzuziehen.
-
void writeString(std::fstream &file, std::string &str) { file << str.length() << ' '; //write length and seperator file << str; //write string } std::string readString(std::fstream &file) { int len; file >> len; // Read length file.ignore(); //skip ' ' std::string data; data.resize(len); //reserve space for string file.read(&data[0], len); //read string return data;
Auch dazu hab ich noch eine (hoffentlich abschließende Frage). Rausgeschrieben wird ja jetzt "Formatiert" und eingelesen "Binary? ". Sollte man das dann nicht gleich handhaben und quasi auch formatiert einlesen? Wäre das dann mit getline ?
-
beg_offl schrieb:
Auch dazu hab ich noch eine (hoffentlich abschließende Frage). Rausgeschrieben wird ja jetzt "Formatiert" und eingelesen "Binary? ". Sollte man das dann nicht gleich handhaben und quasi auch formatiert einlesen? Wäre das dann mit getline ?
Was ist denn der Unterschied, ob du einen String mit << in den Stream schiebst oder mit write? Keiner.
getline ist ziemlich schlecht hier, das ganze Theater hier ist doch nur deshalb gemacht, weil getline nicht passt. Was würde denn passieren, wenn der String ein Trennzeichen enthält?
-
Ja, getline funktioniert mir nicht wirklich habe mal folgendes probiert:
void read_f(){ std::cout << "\nWelcome to read form\n"; std::ifstream datei("test_form.txt", std::ios_base::in); for (int i = 0; i < 3; i++){ size_t len = 0; datei >> len; std::cout << "\nLEN : " << len << "\n"; datei.ignore(); std::vector<char>zeile(len); datei.getline(&zeile[0], len); std::string out(zeile.begin(), zeile.end() ); std::cout << "HERE" << out; out.clear(); } datei.close(); }
Es wird davor 3 x mit datei << len << inhalt in die Datei geschrieben, kann aber nur 1x auslesen. Das liegt an dem Trennzeichen und getline oder? Dachte erst der "Dateizeiger" wandert nicht richtig mit..
-
Noch ne Frage :
ignore() ignoriert einfach das nächste Zeichen oder ?
hatte bis jetzt nur xy.ignore(Zeichenanzahl, "\n"), benutzt...
-
Schau dir die Default-Argumente an.
-
beg_off schrieb:
ignore() ignoriert einfach das nächste Zeichen oder ?
<a href= schrieb:
C++ Reference - istream::ignore">
istream& ignore (streamsize n = 1, int delim = EOF);
Ergo ja.
-
sollte man jetzt eher die Cast Variante :
datei.write(reinterpret_cast<char*>(&myString), myString.length() );
oder die C-String Varainte benutzen?? :
datei.write(myString.c_str(), myString.length() );
Generell hab ich gelesen ist ein reinterpret_cast meist mit Vorsicht zu genießen??
-
Die erste Variante wird explodieren. Die zweite ist unschön, da sie zeigt, dass du das passendere string::data nicht kennst, bzw. nicht den feinen logischen Unterschied zwischen einem C-String und einer Zeichenkette.
-
Die erste Variante wird explodieren
Warum?
dass du das passendere string::data nicht kennst, bzw. nicht den feinen logischen Unterschied zwischen einem C-String und einer Zeichenkette.
Du meinst das "Abschlusszeichen" ?
Ich habe jetzt für "Schreiben und Lesen" mal alle Varianten ausprobiert. (Hier nur die Binary Variante)
Z.B.:
void write_binary(std::string &input, std::fstream &file){ input += '\0'; size_t len = input.length(); file.write(reinterpret_cast<char*>(&len), sizeof(len) ); //file.write(reinterpret_cast<char*>(&input[0]), len /*input.size()*/ ); //file.write(input.c_str(), input.length() ); file.write(&input[0], len); } void read_binary(std::fstream &file){ std::string content; size_t len; file.read(reinterpret_cast<char*>(&len), sizeof(len) ); content.resize(len); file.read(&content[0], len); std::cout << "\n|READ OUT| : " << content << "\n"; }
-
Sorry, Zeile 8 das .size() ist käse
-
Das ist ja auch was völlig anderes. Code ist Logik pur, kein zusammengeschmissener Zeichensalat. Du musst von jedem Zeichen in deinem Code ganz genau wissen, ob und warum du es wo setzt. Das gilt natürlich auch, wenn du hier nach der Richtigkeit von Codebeispielen fragst, denn Ungenauigkeiten in dieser Hinsicht sind in der Programmierung sofort sinnentstellend.
Ich könnte schwören, dass ich dir das alles schon einmal gesagt habe.
-
Das ist ja auch was völlig anderes.
Manchmal sprichst du in Rätseln.
Ich könnte schwören, dass ich dir das alles schon einmal gesagt habe.
Ja, gut möglich. Aber wenn die Scheiße oft nicht so will wie ich will .... F**k gerade am Anfang ist es schon oft deprimierend... Ich weiß nicht, ich glaub oft wenn man nicht soviel mit programmieren am Hut hat, man sich manchmal doch leichter tut am Anfang. Also ich ertappe mich immer wieder das ich mal 3 Kaptiel überspringe, weil ich jetzt XYZ machen will.
-
void writeString(std::fstream &file, std::string &str) { file << str.length() << ' '; //write length and seperator file << str; //write string } std::string readString(std::fstream &file) { size_t len; file >> len; // Read length file.ignore(); //skip ' ' std::string data; data.resize(len); //reserve space for string file.read(&data[0], len); //read string return data; }
Jetzt haben wir hier doch schon seit Ewigkeiten diese funktionierende Variante (hier mal mit size_t, unsere Diskussion ist für den TS vermutlich eh irrelevant).
Warum versucht du denn jetzt wieder irgendwas eigenes zu basteln wobei das die perfekte Lösung wäre? Versuch doch lieber zu verstehen warum wir das so machen und nicht anders.
-
Weil:
Ich habe jetzt für "Schreiben und Lesen" mal alle Varianten ausprobiert
Nur weil ich die "perfekte" Variante danke euch ja bereits habe und auch verstanden habe, heißt es ja nicht, das ich mit mit den anderen Sachen nicht mehr auseinandersetzen muss /kann /will.
Hauptsächlich ging es mir ja darum, welches hiervon:
file.write(input.c_str(), input.length() ); file.write(&input[0], len);
welche Vor / Nachteile hat
-
beg__ schrieb:
Hauptsächlich ging es mir ja darum, welches hiervon:
file.write(input.c_str(), input.length() ); file.write(&input[0], len);
welche Vor / Nachteile hat
<a href= schrieb:
C++ Peference - std::data">Returns a pointer to an array that contains a null-terminated sequence of characters (i.e., a C-string) representing the current value of the string object.
This array includes the same sequence of characters that make up the value of the string object plus an additional terminating null-character ('\0') at the end.
The pointer returned points to the internal array currently used by the string object to store the characters that conform its value.
Both string::data and string::c_str are synonyms and return the same value.
Macht beides das selbe. Mal davon abgesehen dass
string::data
undstring::c_str
am Ende des strings noch ein Nullbyte als Terminator garantieren.