Struct in Datei schreiben aus CodeGuru.com


  • Mod

    nur wahrscheinlich.

    Die vage Definition des Standards ist hier unwichtig. Ich kann dir (ohne nachzusehen) garantieren dass jede gängige existierende Implementierung die auch nur halbwegs relevant sein könnte string so speichert. Zu viel language-lawyerei ist auch nicht gut, besonders wenn man dann - nur um der Theorie zu entsprechen - derartige Performance-Defizite zulässt.



  • @DarkShadow44

    Wahh.. Danke, ich hab die Referenz zu read falsch verstanden. Der Char Pointer ist wo es ingeht, nicht von wo es kommt.
    => Ich dachte die ganze ZEit ich brauche einen CharPointer der auf das erste Zeichen des Strings IN MEINER DATEI zeigt. <=

    F..k, dann ist mir das Beispiel auch klar. Denke so werd ich es dann auch lösen.
    Ich muss echt daran arbeiten, die REfernz besser anzusehen usw.


  • Mod

    Im Jahr 2014 setze ich C++11 voraus. Selbst ohne C++11 ist der Einwand nicht praxisrelevant, die Verbesserung hingegen bringt locker mal 100% Performancegewinn.

    Zu 1 & 2: Schreib die Zahl doch einfach im Klartext! Was soll das Gehacke, mit dem du alles nur unportabel machst?



  • SeppJ schrieb:

    Im Jahr 2014 setze ich C++11 voraus. Selbst ohne C++11 ist der Einwand nicht praxisrelevant, die Verbesserung hingegen bringt locker mal 100% Performancegewinn.

    Ich habe lediglich versucht komplett Standardkonform zu sein.

    SeppJ schrieb:

    Zu 1 & 2: Schreib die Zahl doch einfach im Klartext! Was soll das Gehacke, mit dem du alles nur unportabel machst?

    Wir waren am Anfang bei Binärdateien, insofern bin ich dabei geblieben. Die Endiandess kann man ja noch berücksichtigen.
    Und wenn die streams keine besseren Methoden bieten muss man halt die nutzen die es gibt. 🙂


  • Mod

    DarkShadow44 schrieb:

    SeppJ schrieb:

    Im Jahr 2014 setze ich C++11 voraus. Selbst ohne C++11 ist der Einwand nicht praxisrelevant, die Verbesserung hingegen bringt locker mal 100% Performancegewinn.

    Ich habe lediglich versucht komplett Standardkonform zu sein.

    Selbst dann kannst du direkt den String initialisieren, mittels istreambuf_iterator, ohne Umweg.

    SeppJ schrieb:

    Zu 1 & 2: Schreib die Zahl doch einfach im Klartext! Was soll das Gehacke, mit dem du alles nur unportabel machst?

    Wir waren am Anfang bei Binärdateien, insofern bin ich dabei geblieben. Die Endiandess kann man ja noch berücksichtigen.
    Und wenn die streams keine besseren Methoden bieten muss man halt die nutzen die es gibt. 🙂

    Die kanonische Methode der binären Speicherung eines Strings ist eben: Länge, Trennzeichen, Inhalt. Niemand hat verlangt, die Länge auch binär zu speichern. Das hat doch nur Nachteile!


  • Mod

    Das hat doch nur Nachteile!

    Das ist offenbar falsch. Mit der Annahme dass die Endianness der Maschinen mit denen gelesen bzw. geschrieben wird gleich ist, wird das Schreiben und Parsen laufzeit-effizienter sein (da branch-free) und bei etwas größeren Längen auch weniger Zeichen in die Datei schreiben (im Bezug auf das Datum in welches serialisiert wird). Falls das Kriterien sind gibt es auch Vorteile.
    🤡

    Selbst dann kannst du direkt den String initialisieren, mittels istreambuf_iterator, ohne Umweg.

    Nein, auf gar keinen Fall. Das ist lahmer als Christopher Reeves Beine. Auf manchen Maschinen um Faktor 40.



  • char* pointerToData = "test"/* ... */; 
    int dataLen = 4/* ... */; 
    std::string data; 
    data.append(pointerToData, dataLen);
    

    Die frage bleibt, wo kommt der Zeiger auf char her, wenn ich nur die Länge aus der Datei mit >>len ,gelesen habe.
    Das ist ja was anderes wie read. ??

    Kann das bitte mal jmd erklären?


  • Mod

    Arcoth schrieb:

    Selbst dann kannst du direkt den String initialisieren, mittels istreambuf_iterator, ohne Umweg.

    Nein, auf gar keinen Fall. Das ist lahmer als Christopher Reeves Beine. Auf manchen Maschinen um Faktor 40.

    Sicher? Ich habe momentan keine Lust, das zu messen, aber ich meine mich zu erinnern, dass genau diese Frage schon mal kam und der istreambuf_iterator sehr gut aussah gegenüber read. Und ganz gewiss gegenüber read + vector-Indirektion.


  • Mod

    SeppJ schrieb:

    Sicher?

    http://insanecoding.blogspot.co.uk/2011/11/how-to-read-in-file-in-c.html

    Die Kommentare.

    C/C++: 7.5
    [..]
    iter: 110

    C: 18.3
    C++: 21
    [...]
    iter: 209.3

    Gut, also etwa Faktor 10-15. Bei einigen guten Implementierungen ein kleineres Verhältnis da std::copy wohl für POD-Typen memcpy anwendet sodass mit der ganzen Registerbreite kopiert wird. Irgendwie sowas.


  • Mod

    Arcoth schrieb:

    SeppJ schrieb:

    Sicher?

    http://insanecoding.blogspot.co.uk/2011/11/how-to-read-in-file-in-c.html

    Die Kommentare.

    C/C++: 7.5
    [..]
    iter: 110

    C: 18.3
    C++: 21
    [...]
    iter: 209.3

    Gut, also etwa Faktor 10-15. Bei einigen guten Implementierungen ein kleineres Verhältnis da std::copy wohl für POD-Typen memcpy anwendet sodass mit der ganzen Registerbreite kopiert wird. Irgendwie sowas.

    Irgendwelche ausgewählten Kommentare zu irgendeinem Blog als Quelle? Wer weiß, wer da was wie gemessen hat? Und die Kommentare, die nicht so extrem sind, unterschlägst du auch noch? Bei einem der zitierten steht VS 2005 als Compiler, nicht gerade moderner Standard. Beim Originalblog ist der Faktor 2-2.5, das ist schon normaler.



  • Leute, ganz ruhig bleiben.
    Wie schauts aus, wie soll man es jetzt richtig machen.
    Ist das von DarkSchadow jetzt nicht empfehlensWert?
    Das läuft bisschen aus dem Ruder. Ihr verunsichert mich mehr.

    Übrigens hat keine_Ahnung recht, das mit dem char pointer ist immer noch nicht geklärt, da gehts ja nicht um read.

    Also , wie macht man das am schönsten, bzw wie hat es sich bewährt.



  • Du solltest dich erstmal mit den Unterschieden von binaerem und formatiertem lesen/schreiben befassen. Bevor du dich nicht entschieden hast, was du eigentlich willst, ist es schwierig, dir zu helfen.

    Um es nochmal klarzustellen: operator << und >> schreiben formatiert, waehrend read und write Bytes binaer schreiben.

    Willst du binaer schreiben, dann kannst du das, was ich dir gezeigt habe, einfach ausbauen. Ein String ist nicht viel mehr als Laenge + Bytes, also schreibst du die Laenge raus und danach die Bytes des Strings. Beim Einlesen drehst du das ganze um. Zuerst Laenge einlesen, dann genuegend Speicher besorgen "str.resize(len);" und dann in den String einlesen "stream.read(&str[0], len);".

    Die Frage nach dem Typen fuers speichern der Laenge: Das haengt davon ab, wie lang deine Strings werden sollen und ob dir Speicherverbrauch wichtig ist. Wenn deine Strings nicht laenger als 4GB werden und dir ein paar Bytes mehr bei kurzen Strings nichts ausmachen, wuerde ich einfach uint32_t nehmen. Wenn kein Byte verschwendet werden soll kann man mit VarInts tricksen.

    Und wenn du formatiert schreiben moechtest, machst du es so wie SeppJ. Laenge raus mit <<, danach Leerraum oder ein Trennzeichen (ich wuerde sagen Leerraum ist sogar einfacher) und dann den String selbst.

    Und zum Abschluss noch meine persoenliche Meinung, vielleicht hilft dir das bei der Entscheidung. Generell sind Binaerfiles einfacher zu handhaben, weil man sich laestiges Parsing (bzw im umgekehrten Schritt generieren des Formats) erspart. Bei binaerer IO schreib ich einfach ein Objekt nach dem anderen raus und das wars. Die Probleme mit Portabilitaet, von denen dauernd gesprochen wird, sind nicht so gross, wie manche hier tun. Byte-Order laesst sich ganz einfach umdrehen und float/double Formate sind genormt mit IEEE 754 wenn ich die Nummer richtig in Erinnerung hab.
    Binaere IO kann nur manchmal unpraktisch sein, wenn man ein lesbares File haben moechte. Das kann der Fall sein wenn man ein Config-File haben moechte, oder wenn man gerade auf Fehlersuche ist. Hex-Editoren helfen nur bedingt.

    Edit: Und noch was zu istreambuf_iterator: Warum sich irgendjemand dieses Gehacke antun soll, verstehe ich nicht. Es ist weder schoener, noch einfacher zu verstehen und schon gar nicht schneller. read() und write() sind King. Fang dir diesen Quatsch gar nicht erst an.

    Edit 2: Und dass manche Leute hier jedes Mal aufs neue Messungen verlangen, wenns um istream(buf)_iterator vs read geht, ist einfach nur noch laecherlich. Wir hatten diese Vergleiche schon zig mal, und in so ziemlich jedem Fall ist rausgekommen, dass Iteratoren signifikant langsamer sind. Findet euch damit ab.


  • Mod

    Kellerautomat schrieb:

    Edit 2: Und dass manche Leute hier jedes Mal aufs neue Messungen verlangen, wenns um istream(buf)_iterator vs read geht, ist einfach nur noch laecherlich. Wir hatten diese Vergleiche schon zig mal, und in so ziemlich jedem Fall ist rausgekommen, dass Iteratoren signifikant langsamer sind. Findet euch damit ab.

    Klar sind die langsamer als read. Aber langsamer als die Implementierung mit dem temporären Zwischenvector? Wohl kaum.



  • SeppJ schrieb:

    Klar sind die langsamer als read. Aber langsamer als die Implementierung mit dem temporären Zwischenvector? Wohl kaum.

    Kann ich mir sehr gut vorstellen, dass das langsamer ist. Zumal man eben keinen Zwischenvektor braucht.


  • Mod

    Kellerautomat schrieb:

    SeppJ schrieb:

    Klar sind die langsamer als read. Aber langsamer als die Implementierung mit dem temporären Zwischenvector? Wohl kaum.

    Kann ich mir sehr gut vorstellen, dass das langsamer ist. Zumal man eben keinen Zwischenvektor braucht.

    Lies den Thread. Es ging um eine ganz streng C++98-konforme Implementierung (Speicherlayout von string kann nicht-kontinuierlich sein), da kommt man tatsächlich nicht ohne Zwischenvector aus, wenn man keine Iteratoren will.
    (Wobei, wenn ich mich recht entsinne, in C++98 theoretisch ein standardkonformer vector möglich wäre, der intern rückwärts im Speicher liegt. In dem Fall wären die Iteratoren sogar die einzige pedantisch portable Methode)



  • keine ahnung schrieb:

    char* pointerToData = "test"/* ... */; 
    int dataLen = 4/* ... */; 
    std::string data; 
    data.append(pointerToData, dataLen);
    

    Die frage bleibt, wo kommt der Zeiger auf char her, wenn ich nur die Länge aus der Datei mit >>len ,gelesen habe.

    Das war nur ein unpassendes Beispiel wie du N chars aus einem pointer in einen string kopierst.. Vergiss das bitte wieder, hat für dich keine Relevanz. 🙂
    Das war nur für den Fall dass du keine streams hast, sorry wollte dich nicht verwirren. 😞

    Nimm einfach:

    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;
    

    So sollte es jetzt aber endlich passen. Die Zahl wird als Text in die Datei geschrieben, dann ein Trennzeichen um die Zahl vom string abzugrenzen, und dann der string.
    Wenn jemand ne Lösung hast wie man das Trennzeichen besser überspringt nur her damit.



  • int fuer Laengen ist ne Schnapsidee.



  • Kellerautomat schrieb:

    int fuer Laengen ist ne Schnapsidee.

    In 99% der Fälle ist ein int größer als 16Bit, d.h. mindestens 32Bit und damit völlig ausreichend. In welchem Fall könnte das denn zum Problem werden ?
    Aber gut, machen wir ein "uint32_t" draus. 😃


  • Mod

    Weil ein String groesser als 2(4) GiB gross werden kann.
    Weil der Extraktionsoperator ein Minuszeichen vor der Laenge als korrekt sieht und eine negative Laenge setzt.

    Nimm std::size_t oder std::string::size_type , die duerften auf 64-Bit Systemen auch 8 Byte gross sein.



  • Arcoth schrieb:

    Weil ein String groesser als 2(4) GiB gross werden kann.

    Aber kein normaler string sollte so lang werden. Und wenn doch hast du ein Designproblem.
    Andere Sprachen limitieren die Länge von strings auch auf 32Bit Integer, und ich habe noch nie gehört dass das ein Problem darstellt. 😉

    Arcoth schrieb:

    Weil der Extraktionsoperator ein Minuszeichen vor der Laenge als korrekt sieht und eine negative Laenge setzt.

    Kommt aber im normalen Gebrauch nie vor. Und wenn ich das Program crashen will, kann ich auch die Länge zu groß/klein machen, oder gleich weglassen...


Anmelden zum Antworten