Struct in Datei schreiben aus CodeGuru.com



  • cpp_beginner_offl schrieb:

    Was wenn meine Strukt nicht POD ist? z.B.: einen std::string enthält, oder enthalten soll?

    Dann machst dus so wie Kellerautomat gesagt hat: Nicht dei struct einfach reinschreiben sondern jeden Member einzeln.
    Für string-member gibts 3 Möglichkeiten:

    • Nullbasiert, dh strings als C-string inklusive Nullbyte reinschreiben
    • Fixed size (d.h. immer gleich viele chars)
    • Die Länge des strings und dann den Inhalt

    Je nach Anforderungen. Ich würde eher zu Size+Inhalt tendieren. 🙂



  • •Die Länge des strings und dann den Inhalt
    Je nach Anforderungen. Ich würde eher zu Size+Inhalt tendieren.

    Ok, das leuchtet schon ein, aber wie lese ich das dann wieder ein?
    Mit der Länge und new[länge] ein char array anlegen?

    Und noch was :

    os.write(static_cast<char const*>(data), size);
    
       static_cast  oder reinterpret_cast  ... warum nicht ganz ohne Cast? 
    
    irgendwas.write( (char*)&myStruct sizeof(myStruct) );
    


  • beg_offl schrieb:

    Ok, das leuchtet schon ein, aber wie lese ich das dann wieder ein?
    Mit der Länge und new[länge] ein char array anlegen?

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

    Oder wenn du es mit streams machst, kannst du die streams gleich alles machen lassen:

    fstream stream;
    stream >> data;
    

    beg_offl schrieb:

    Und noch was :

    os.write(static_cast<char const*>(data), size);
    
       static_cast  oder reinterpret_cast  ... warum nicht ganz ohne Cast? 
     
    irgendwas.write( (char*)&myStruct sizeof(myStruct) );
    

    Das ist doch auch ein Cast. Allerdings ein C-Style Cast. Da wir hier in C++ sind, nutzen wir auch C++-Style Casts.



  • DarkShadow44 schrieb:

    beg_offl schrieb:

    Ok, das leuchtet schon ein, aber wie lese ich das dann wieder ein?
    Mit der Länge und new[länge] ein char array anlegen?

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

    Oder wenn du es mit streams machst, kannst du die streams gleich alles machen lassen:

    fstream stream;
    stream >> data;
    

    Ok, append muss ich erst in der eferenz nachsehen.

    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?

    Generell sind wohl char Arrays in C++ nicht mehr angebracht ?



  • beg_offl schrieb:

    Generell sind wohl char Arrays in C++ nicht mehr angebracht ?

    Strings, die man bastelt, einliest und so, sollten keine char-Arrays mehr sein.
    Konstante Strings, die man eh nur dem Betriebssystem reicht, dürfen schon.

    string const filename="c:/autoexec.bat";//grotesk
    ...
    ifstream in(filename);
    


  • DarkShadow44 schrieb:

    beg_offl schrieb:

    Ok, das leuchtet schon ein, aber wie lese ich das dann wieder ein?
    Mit der Länge und new[länge] ein char array anlegen?

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

    Oder wenn du es mit streams machst, kannst du die streams gleich alles machen lassen:

    fstream stream;
    stream >> data;
    

    Hmm, da hab ich jetzt doch noch ein anderes Problem. Wenn der String mit Zahlen beginnt....

    Ich schreibe raus mit : datei << length ; datei << myString .
    Beim Einlesen : datei >> len => wenn der String jetzt mit Zahlen beginnt, hab ich bei Länge Mist drin stehen


  • Mod

    Dann schieb Leerraum dazwischen. Bei Leerraum brechen formatierte Extraktionen nämlich ab. Also

    datei << length << ' ' << myString;
    

    zum schreiben und einlesen wie gewohnt.



  • OK, auf die Variante kam ich auch schon. Dann muss ich zur Länge 1 dazu rechnen, aber ich dachte es geht evtl doch noch eleganter (was hald bei dieser Version elegant ist 😃)


  • Mod

    beg_offl schrieb:

    Dann muss ich zur Länge 1 dazu rechnen

    Wieso?

    , aber ich dachte es geht evtl doch noch eleganter

    Du kannst gerne noch ein 10000 Zeilen Templatemonster davor schreiben, das es dir ermöglicht, alles und jeden Typen auf die gleiche einfache Art und Weise zu serialisieren. Ich schlage vor, das Resultat zu veröffentlichen, da viele Leute da dran interessiert wären. "Boost Serialization" wäre ein guter Name 🙂 .



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


Anmelden zum Antworten