Binary File schreiben



  • Hallo,

    ich habe einen Code, welcher Werte aus einer Datei auslesen, diese Verdoppeln und wieder zurückschreiben soll.

    Der Code kann bisher die Werte einlesen. Er wurde nicht von mir geschrieben, aber ich will ihn modifizieren. Meine Kenntnisse sind eher stark beschränkt und ich verstehe nicht so ganz wie das in Binary Files schreiben funktioniert.

    Ich habe ein wenig gegoogelt aber irgendwie verstehe ich es noch nicht.

    Der Code sieht jetzt wie folgt aus:

    ifstream radienFileStream;
    string radpath=path+"radien.bin";
    radiiFileStream.open(radpath.c_str(),ios::in | ios::binary);
    
    double radien[nMax];
    radiiFileStream.read((char*) &radien, sizeof(double)*nMax);
    

    nMax ist die Anzahl der Werte in der .bin Datei.
    Wahrscheinlich geht das viel besser, aber ich muss damit arbeiten und darf das nicht verändern.

    Ich will jetzt die Anzahl der Radien verdoppeln, sprich jeder Radius soll zweimal vorkommen und dann wieder in eine neue .bin Datei geschrieben werden.

    Wie ich die Anzahl verdopple etc ist mir klar, ich weiß nur nicht, wie ich wieder das Array als .bin Datei schreibe. Geschweige denn wie das ganze überhaupt formatiert ist.

    weiter unten habe ich noch ein

    double positionen[nMax][3]
    	positionenFileStream.read((char*) &positionen, sizeof(double)*nMax*3);
    

    Der Filestream schreibt ja in das Array Positionen, das ist nMax lang und 3 breit. Aber wie funktioniert das einlesen? Liest es einfach Werte ein und füllt das Array der Reihe nach auf? Was bedeutet das sizeof?

    Geht das auf die Art:

    std::ofstream schreiben("example.bin", std::ios::out | std::ios::binary | std::ios::app)
    
    schreiben.write(radien[nMax], sizeof radien);
    

    was bedeutet eigentlich das sizeof ?

    Sry für die blöden Fragen!



  • RubenRybnick schrieb:

    Er wurde nicht von mir geschrieben, aber ich will ihn modifizieren...
    aber ich muss damit arbeiten und darf das nicht verändern.

    Was denn nun?
    sizeof gibt die Größe eines Objektes oder eines Typs in Bytes zurück.
    Bei Arrays also die Größe des gesamten Arrays in Bytes.

    double radien[nMax];
    radiiFileStream.read((char*) &radien, sizeof(double)*nMax);
    

    ist kompletter Müll und zeigt wieder mal, dass C++ler keine Ahnung von Zeigern haben und sich meist irgendwas zusammencasten, nur damit der Compiler Ruhe gibt.

    Korrekt wäre

    const int nMax = 100000;
    ...
    double radien[nMax];
    ...
    radiiFileStream.read((char*)radien, sizeof radien);
    

    Dein "Verdoppeln" ist missdeutig, und setzt voraus, dass das Programm das die Datei schrieb dieselbe double-Repräsentation und Byteorder verwendet wie dein Programm.
    Wie soll das "Verdoppeln" denn aussehen? Das gesamte Array hinter dem Original-Array oder oder jedes Array-Element gefolgt von Kopie?
    Für Variante 1 wäre das doch sehr einfach, was ist daran so schwer?

    std::ofstream schreiben("example.bin", std::ios::out | std::ios::binary | std::ios::app)
    schreiben.write((char*)radien, sizeof radien);
    schreiben.write((char*)radien, sizeof radien);
    


  • Hi,

    ich versteh nicht komplett wie das schreiben funktioniert. Ich kann ja nicht einfach in eine bin Datei schauen und sehen ob es das richtige geschrieben hat.

    Ich hab das Array Radien. Ich hab eine schleife gebaut, die genau macht was ich will. Sie baut ein neues Array, Name jetzt egal, nennen wir es Radi. Das Array ist viel länger. Teilweise doppelt so lang, aber auch dreimal etc.

    Mein Problem ist jetzt, wie kann ich das schreiben, so dass das gleiche Programm das wieder lesen und nochmal vergrößern kann?

    std::ofstream schreiben("example.bin", std::ios::out | std::ios::binary | std::ios::app)
    schreiben.write((char*)radien, sizeof radien);
    schreiben.write((char*)radien, sizeof radien);
    

    Wie steht da

    schreiben.write((char*)radien, sizeof radien);
    

    Ich versteh nicht ganz wie das ausschaut. Ist zwischen den Zahlenwerten ein Leerzeichen? Oder wie weiß die Funktion, wann eine Zahl aufhört und eine neue anfängt? Würde das schreiben.write das komplette Array schreiben oder nur einen Wert? Die Datei ist bei mir nur 1kb groß, obwohl die Ursprungsdatei ~3mb hat. Irgendwie wurde nicht alles kopiert.

    Würde das einfach mit deinem Code funktionieren?

    So sieht das bisher aus

    //read radii
    	double radii[nMax];
    	radiiFileStream.read((char*) &radii, sizeof(double)*nMax);
    	rad=new double[nMax];
    	for(int i=0;i<nMax; i++){
    		rad[i]=radii[i];	//copy radii to global array rad
    	}
    
        std::ofstream schreiben("radi2.bin", std::ios::out | std::ios::binary | std::ios::app);
    
                schreiben.write((char*)radii, sizeof radii);
    

    Ich will jetzt erstmal genau die gleiche Datei nochmal zu schreiben um zu sehen ob es funktioniert. Leider Funktioniert es nicht. Ich verstehe nicht warum.


  • Mod

    Die Definition des Streams lässt sich so verkürzen, falls es dich interessiert:

    ifstream radienFileStream(path + "radien.bin", ios::binary); // Seit C++11 kann es auch ein std::string sein - sonst noch Klammern drum und ein .c_str() ran
    // ios::in ist bei ifstream implizit - ebenso wie ios::out bei ofstream
    

    Ist zwischen den Zahlenwerten ein Leerzeichen?

    Nein.

    Ich verstehe nicht warum.

    Hast du geprüft ob die Datei geöffnet wurde?

    [...] kompletter Müll und zeigt wieder mal, dass C++ler keine Ahnung von [..] haben und sich meist irgendwas zusammencasten, nur damit der Compiler Ruhe gibt

    Es reicht langsam mit deinen vehementen "Kritiken"! 👎

    Und was genau daran ist übrigens Müll? Dass er da ein unnötiges Und-Zeichen stehen hat?



  • Arcoth schrieb:

    Und was genau daran ist übrigens Müll? Dass er da ein unnötiges Und-Zeichen stehen hat?

    Versteh ich auch nicht.

    Das sizeof(double)*Blub find' ich nicht optimal (besser sich gleich die Array-Grösse holen), aber falsch ist es nicht.
    Der überflussige & genauso.
    Und die unnötigen Klammern beim sizeof sind SO verbreitet dass die meisten Leuter erstmal GANZ doof gucken wenn sie sizeof ohne Klammern sehen.
    Und man hätte nen C++ Cast ( reinterpret_cast ) verwenden können.
    Der ist leichter "suchbar".



  • Hi,

    danke für die Antworten. Ob das jetzt besser machbar gewesen wäre ist mir eigentlich egal. Das hab ich nicht gemacht und an dem Einlesen will ich nichts ändern.

    Wenn ich jedenfalls

    double radii[nMax];
    	radiiFileStream.read((char*) &radii, sizeof(double)*nMax);
       std::ofstream schreiben("radi2.bin", std::ios::out | std::ios::binary | std::ios::app);
    
                schreiben.write((char*)radii, sizeof radii);
    

    verwende, dann ist die geschriebene Datei nicht gleich der Originalen. Ich verstehe nicht warum.

    Ich hab das mittlerweile angepasst und verwende

    schreiben.write((char*) &radii, sizeof(double)*nMax);
    

    Aber das funktioniert auch nicht 100%. Der erste Wert ist total falsch.



  • hustbaer schrieb:

    Und man hätte nen C++ Cast ( reinterpret_cast ) verwenden können.
    Der ist leichter "suchbar".

    Will den ja nicht mehr suchen, bzw hier ist er gut und will nicht, daß er mir beim Suchen nach echten Problemen dauernd vor die Flinte kommt. scnr.



  • volkard schrieb:

    hustbaer schrieb:

    Und man hätte nen C++ Cast ( reinterpret_cast ) verwenden können.
    Der ist leichter "suchbar".

    Will den ja nicht mehr suchen, bzw hier ist er gut und will nicht, daß er mir beim Suchen nach echten Problemen dauernd vor die Flinte kommt. scnr.

    Ich versteh hier echt nur Bahnhof sry...



  • volkard schrieb:

    hustbaer schrieb:

    Und man hätte nen C++ Cast ( reinterpret_cast ) verwenden können.
    Der ist leichter "suchbar".

    Will den ja nicht mehr suchen, bzw hier ist er gut und will nicht, daß er mir beim Suchen nach echten Problemen dauernd vor die Flinte kommt. scnr.

    Dann schreib dir ne Hilfsfunktion

    template <class T>
    char* char_pointer_alias(T* t)
    {
        return reinterpret_cast<char*>(t);
    }
    
    template <class T>
    char const* char_pointer_alias(T const* t)
    {
        return reinterpret_cast<char*>(t);
    }
    

    @RubenRybnick
    Ich ziehe Sprachkonstrukte die man suchen kann (z.B. "Find in Files" mit Regex Pattern) welchen vor die man nicht suchen kann. Speziell wenn es um Dinge geht wo man leicht 'was falsch machen kann. Wie eben beim Casten.

    Einen Funktionsaufruf kann ich suchen, einfach mit dem Funktionsnamen. Klar bekommt man damit u.U. viele false positives, aber dafür findet man alle Stellen wo die Funktion referenziert wird.
    (Indirekte Aufrufe über Funktionszeiger findet man natürlich nicht, aber dafür die Stellen wo diese Zeiger initialisiert werden.)

    Ebenso kann man suchen wo Klassen oder Variablen referenziert werden.

    Die C++ Casts (static_cast, dynamic_cast, const_cast und reinterpret_cast) lassen sich auch super suchen.
    C-Style Casts ... dummerweise nicht. Speziell wenn du Stellen suchen willst wo etwas ganz bestimmtes gemacht wird, z.B. eben const wegcasten ( const_cast ) oder zwischen ganz unverwandten Typen casten ( reinterpret_cast ).

    => C++ Casts verwenden.



  • RubenRybnick schrieb:

    Wenn ich jedenfalls

    double radii[nMax];
    	radiiFileStream.read((char*) &radii, sizeof(double)*nMax);
       std::ofstream schreiben("radi2.bin", std::ios::out | std::ios::binary | std::ios::app);
    
                schreiben.write((char*)radii, sizeof radii);
    

    verwende, dann ist die geschriebene Datei nicht gleich der Originalen. Ich verstehe nicht warum.

    std::ios::app ?
    std::ios::app heisst "häng an ein bestehendes File an". Ist das wirklich das was du willst?
    Denn wenn vorher schon 'was in dem File steht...
    Ich würde das mal weglassen.

    =>
    std::ofstream schreiben("radi2.bin", std::ios::out | std::ios::binary);



  • hustbaer schrieb:

    std::ofstream schreiben("radi2.bin", std::ios::out | std::ios::binary);

    die Verknüpfung mit ios::out ist übrigens automatisch, musst du nicht angeben.


Anmelden zum Antworten