Struct in Datei schreiben aus CodeGuru.com



  • Hab Momentan keine Zeit daran groß weiter zu machen, aber wenn dann werd ich´s hier reinstellen um mir meine "Watsche" abzuholen . 🙂 🙂

    Ähm, Sepp, wie schon mal geschrieben, ich bin noch nicht bei Templates, also werd ich selbst auch keines erstellen. Das ganze ist rein aus "hey ich hab ne Strukt mit nem String, schreib das mal auf einmal raus" geboren.



  • Das versteh ich nicht ganz, wie ich "dahin" kommen soll:

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

    ich lese erst die länge mit

    datei >> len ; ein.

    so, wie krieg ich jett nen char Pointer wie in dem obrigen Beispiel? (Das Rausschreiben hab ich jetzt ums ' ' ergänzt.

    Sorry, Leute, für euch ist das bestimmt kinderkacke, aber ich hab momentan nicht soviel Zeit mich länger damit zu beschäftigen. Und ich bin hald noch nicht soo weit mit c++



  • gar keiner?



  • Und hat evtl. noch jmd. einen Tip für ne einigermaßen gute OFFLINE Referenz?


  • Mod

    beginner_offl schrieb:

    Und hat evtl. noch jmd. einen Tip für ne einigermaßen gute OFFLINE Referenz?

    cppreference bietet ein Offline-Archiv an.



  • beg_offl schrieb:

    stream >> data => das geht dann aber nur wenn in der Datei nur Text steht , bzw. ich alles alles in den String data einlesen will, hab ich das jetzt richtig verstanden?

    Nein. Du kannst in C++ auch binär schreiben und lesen.

    beginner_offl schrieb:

    so, wie krieg ich jett nen char Pointer wie in dem obrigen Beispiel? (Das Rausschreiben hab ich jetzt ums ' ' ergänzt.

    Warum nicht einfach binär ?

    #include <string>
    #include <fstream>
    #include <vector>
    
    void writeString(std::fstream &file, std::string &str)
    {
    	file << (int)str.length();
    	file << str;
    }
    
    std::string readString(std::fstream &file)
    {
    	int len;
    	file >> len;
    	std::vector<char> buffer(len);
    	file.read(&buffer[0], len);
    	return std::string(buffer.begin(), buffer.end());
    }
    
    void testWrite()
    {
    	std::fstream file("testce.txt", std::ios::binary|std::ios::out);
    
    	std::string s1 = "Hallo";
    	std::string s2 = "Welt";
    
    	writeString(file, s1),
    	writeString(file, s2);
    
    	file.close();
    }
    void testRead()
    {
    	std::fstream file("testce.txt", std::ios::binary|std::ios::in);
    
    	std::string s1 = readString(file);
    	std::string s2 = readString(file);
    
    	file.close();
    }
    int main()
    {
    	testWrite();
    	testRead();
    
    	return 0;
    }
    

    beginner_offl schrieb:

    Und hat evtl. noch jmd. einen Tip für ne einigermaßen gute OFFLINE Referenz?

    Dritter Treffer bei Google.


  • Mod

    @Darkshadow44:
    -Das geht schief, wenn der String mit einer Zahl beginnt -> Trennzeichen vergessen
    -Wozu der Cast nach int? Das Einzige, was du dadurch erreichst, ist doch, dass es für lange Strings nicht mehr funktioniert.
    -Lies doch direkt in den String! Wozu der vector? Strings sind garantiert am Stück gespeichert.



  • SeppJ schrieb:

    @Darkshadow44:
    -Das geht schief, wenn der String mit einer Zahl beginnt -> Trennzeichen vergessen
    -Wozu der Cast nach int? Das Einzige, was du dadurch erreichst, ist doch, dass es für lange Strings nicht mehr funktioniert.
    -Lies doch direkt in den String! Wozu der vector? Strings sind garantiert am Stück gespeichert.

    1. Oh, ich dachte die Operatoren "<<" und ">>" könnten auch zum schreiben von Binärdaten genutzt werden... 😮
      Korrektur ohne Rücksicht auf Endianess:
    //Read
    //file >> len;
    file.read((char*)&len, sizeof(len));
    
    //Write
    //file << (int)str.length();
    int len = str.length();
    file.write((char*)&len, sizeof(len));
    
    1. Ok ich sollte unsigned int verwenden, oder besser uint_32t. Die Maximale Länge eines strings ist auf 32Bit Systemen übrigends auch nur 4 Bytes.
      "std::string::size_type" würde ich nicht werwenden (sogar davon abraten), da die Länge auf 32Bit Systemen 4 Bytes ist, auf 64Bit Systemen aber 8 Bytes.
      Was spricht dagegen es immer auf 32Bit zu limitieren, und sich dafür 32Bit und 64Bit Versionen der Programme gleich verhalten ?
    2. Sicher dass strings auch vor C++11 garantiert am Stück sind ? Laut diesem Stackoverflow Post ist das in C++03 noch nicht garantiert, nur wahrscheinlich.
      C++11 Variante:
    //std::vector<char> buffer(len);
    //file.read(&buffer[0], len);
    //return std::string(buffer.begin(), buffer.end());
    data.resize(len);
    file.read(&data[0], len);
    return data;
    

  • 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.


Anmelden zum Antworten