Dateioperationen, ofstream, Integerwerte speichern



  • Hallo Leute,

    ich bin neu hier im Forum und fange gerade an mich mit C++ zu beschäftigen. Davor habe ich bereits einige Jahre Erfahrung in der Programmierung mit Blitz Basic / Pure Basic gemacht und hauptsächlich diverse kleine Spiele programmiert (Asteroids, Sokoban usw.) Letzteres möchte ich jetzt in C++ programmieren.

    Dabei habe ich noch Probleme mit den Dateioperationen. Ich habe ein zweidimensionales Array, welches Integerwerte enthält. Dieses möchte ich in einer Datei speichern. Das Problem besteht jetzt darin, dass alles was in der Datei gespeichert wird, als reiner Text gespeichert wird. Dabei ist es egal welchen Datentyp ich versuche zu speichern. Selbst eine Float-Variable wird in einen String umgewandelt und z.B. als "3.14159" in der Datei gespeichert.

    Um das Problem zu verdeutlichen hier mal die Funktion, die ich zum speichern verwende:

    void savearraytofile(int array[MAP_WIDHT][MAP_WIDHT], const char *filename){
    
        std::ofstream file;
        file.open(filename, std::ios::out);
    
        for (int y = 0; y < MAP_HEIGHT; y++) {
            for (int x = 0; x < MAP_WIDHT; x++) {
                
                int temp;           // funktioniert nicht
                //double temp;      // funktioniert nicht
                //char temp;        // funktioniert
    
                temp = array[y][x];
                file << temp;       // speichert immer als char
            }
        }
    
        file.close();
    

    Die Datei sieht dann so aus:

    1100000011100000000100000010000000001100011111111001111111100000001100000000100010000000011100000011
    

    Jetzt könnte ich die Daten natürlich als Char einlesen und dann wieder in Integer umrechnen. Wenn ich nur Werte von 0-9 verwende wäre das recht einfach:

    void loadarrayfromfile(int array[MAP_WIDHT][MAP_WIDHT], const char *filename) {
      
        std::ifstream file;
        file.open(filename, std::ios::in);
    
        for (int y = 0; y < MAP_HEIGHT; y++) {
            for (int x = 0; x < MAP_WIDHT; x++) {  
                
                // file >> array[y][x];         // funktioniert nicht
    
                char temp;
                file >> temp;
                array[y][x] = temp;             
    
                array[y][x] = array[y][x] - 48; // ASCII to Int
            }
        }
      
        file.close();
    }
    

    Das ist aber natürlich nicht sehr sinnvoll, da ich als Integer speichern und wieder auslesen möchte.
    Selbst wenn ich die Datei im "Binärmodus" --- file.open(filename, std::ios::binary); --- öffne, wird alles immer als char gespeichert. Was habe ich da übersehen bzw. wie speichert man Daten unterschiedlicher Datentypen? Laut Befehlsreferenz soll man mit fstream ja auch float, int ect. speichern können...


  • Mod

    Du willst das, was in Befehlsreferenzen unter "unformatierte" Ausgabe steht, also write (oder put). Der Operator << ist für formatierte Ausgaben, sprich für etwas, das auch ein Mensch lesen kann. Bei write bist du aber selber dafür verantwortlich für Größenangaben, also sei dir sicher, dass du weißt, was du tust. Du bist auch selber dafür verantwortlich, sicher zu sein, ob das überhaupt funktioniert. Beispielsweise kann ein Wert, der auf diese Weise mit einem bestimmten System geschrieben wurde, eventuell nicht mit einem anderen System gelesen werden, falls intern unterschiedliche Binärformate benutzt werden.



  • Danke für die Antwort. Das hatte ich noch nicht versucht, da diese Funktion laut Referenz den Datentyp "const char" als Parameter erwartet

    Zitat:

    ostream& write (const char* s, streamsize n);
    

    Wenn ich versuche, einen Integer-Wert zu übergeben, erhalte ich auch eine entsprechende Fehlermeldung:

    Schweregrad	Code	Beschreibung	Projekt	Datei	Zeile	Unterdrückungszustand
    Fehler (aktiv)	E0167	Das Argument vom Typ ""int"" ist mit dem Parameter vom Typ ""const char *"" inkompatibel.	ArrayTest	D:\Programmierung\Cpp\ArrayTest\ArrayTest\ArrayTest.cpp	84
    

    Das man mit dem Operator zwar alle Datentypen zuweisen kann, diese jedoch in char umgewandelt werden, hatte ich schlicht überlesen.🤫

    folgendes funktioniert allerdings:

     file.put(array[y][x]);
    
     array[y][x] = file.get();
    

    Damit wäre das Problem gelöst, danke für den Input. 🙂



  • @Zothac übergib write() einen (char) pointer auf das erste Byte des Wertes den Du schreiben willst und als size die Anzahl an Bytes die der zu schreibende Typ breit ist. Lesen analog mit read().



  • @Zothac sagte in Dateioperationen, ofstream, Integerwerte speichern:

    da diese Funktion laut Referenz den Datentyp "const char" als Parameter erwartet

    Ist der * durch die Formatierung verloren gegangen oder hast du ihn nicht gesehen/verstanden?

    Es ist const char*



  • Mit const char* s ist in diesem Fall nicht nur String gemeint. C++ unterscheidet hier nicht zwischen char und "byte" (wie andere Sprachen ;-).
    Du kannst also, so wie @Swordfish schon geschrieben hat, einfach einen Zeiger auf einen beliebigen Datentyp übergeben, z.B.

    int x = 42;
    file.write(&x, sizeof(int));
    

    Die Datei dann aber im Binary-Modus benutzen (zumindestens unter Windows relevant).

    PS: Mit put schreibst du nur ein einzelnes char, d.h. wenn in deinem int-Array größere Werte als -128 bis 127 stehen, dann wird nur das niederwertige Byte weggeschrieben (wegen "promotion").



  • Dazu müsste ich einen Zeiger vom Typ char auf eine Integer-Variable zeigen lassen. Das führt zur Fehlermeldung.

            int value1 = 12345;
            char *ptr1;
            ptr1 = &value1;
    
    Schweregrad	Code	Beschreibung	Projekt	Datei	Zeile	Unterdrückungszustand
    Fehler (aktiv)	E0513	Ein Wert vom Typ ""int *"" kann keiner Entität vom Typ ""char *"" zugewiesen werden.	ArrayTest	D:\Programmierung\Cpp\ArrayTest\ArrayTest\ArrayTest.cpp	126	
    
    


  • Du musst schon casten: char *ptr1 = reinterpret_cast<char*>(&value1)



  • @Th69 sagte in Dateioperationen, ofstream, Integerwerte speichern:

    file.write(&x, sizeof(int));

    Besser wäre imho file.write(&x, sizeof(x));
    Weil man da den Typ von x nicht unbedingt wissen muss.



  • Ich weiß, daß andere es so machen, aber ich bevorzuge die explizite Typangabe, denn ich habe schon solchen Code gesehen:

    const char *s = "...";
    file.write(s, sizeof(s)); // weil da anscheinend nur per C&P Code erstellt wurde
    

    Und bei Einsetzen des Typen sollte einem Auffallen, daß das so nicht funktioniert (zumindestens, wenn man den String ganz ausgeben will, und nicht nur die ersten 4/8/... Zeichen ;-).

    Außerdem habe ich auch die Typumwandlung oben vergessen:

    int x = 42;
    file.write(reinterpret_cast<const char *>(&x), sizeof(int)); // sizeof(x)
    


  • Danke schön. In Basic war das alles etwas einfacher...



  • Da gibt es ja auch keine Zeiger!



  • @Zothac Das wofür es fertige Funktionen in BASIC gibt ist meist in BASIC einfacher. Das wofür es keine fertigen Funktionen gibt ist dafür oft in C++ einfacher.



  • @hustbaer oder deutlich schneller 😉

    @Th69 Jain... zumindest bei Pure Basic gibt es auch Zeiger. Da musste man sich allerdings wenig Gedanken um Datentypen machen. Es gibt da sog. "Types" welche mit Objekten vergleichbar sind. Da konnte man auch Zeiger auf einzelne Objekte setzen.


Log in to reply