Stream in char* kopieren



  • PhilippF schrieb:

    ...Ich wollte einen Double binär speichern....

    Warum ?
    Ist oftmals keine gute Idee.

    Gruß,

    Simon2.



  • Simon2 schrieb:

    PhilippF schrieb:

    ...Ich wollte einen Double binär speichern....

    Warum ?
    Ist oftmals keine gute Idee.

    Welche Alternative würde es geben? Eine andere Alternative, die mir einfällt, wäre ihn als String zu speichern. Nur das macht das Einlesen und Auslesen durch die Konvertierungen wirklich langsam.



  • PhilippF schrieb:

    ...Eine andere Alternative, die mir einfällt, wäre ihn als String zu speichern. Nur das macht das Einlesen und Auslesen durch die Konvertierungen wirklich langsam.

    Hast Du das mal ausprobiert ?
    Also das soll jetzt nicht unfreundlich klingen, aber in mindestens 90% der Fälle hier sind solche "Performanceverlustängste" vollkommen unbegründet ... und in 90% der verbleibenden Fälle gibt's bessere Lösungen für (nachgewiesene) Performanceprobleme.

    Du weißt schon, dass Binärspeichern Compiler-/Plattform-/Einstellungs-/...abhängige Files erzeugt, oder ? Wenn Du also später mal diese Files wieder einlesen möchtest, hast Du gute Chancen, die Daten gar nicht mehr einlesen zu können...

    Gruß,

    Simon2.



  • Simon2 schrieb:

    PhilippF schrieb:

    ...Eine andere Alternative, die mir einfällt, wäre ihn als String zu speichern. Nur das macht das Einlesen und Auslesen durch die Konvertierungen wirklich langsam.

    Hast Du das mal ausprobiert ?

    Also das soll jetzt nicht unfreundlich klingen, aber in mindestens 90% der Fälle hier sind solche "Performanceverlustängste" vollkommen unbegründet ... und in 90% der verbleibenden Fälle gibt's bessere Lösungen für (nachgewiesene) Performanceprobleme.

    Keine Sorge, das klingt nicht unfreundlich ;). Ich bin ja auch der, der um Hilfe bittet und da ist mir jede Hilfestellung recht. Aber zu deiner Frage: Ja, die bisherige Lösung sieht so aus, dass die Doubles alle untereinander in eine Textdateigeschrieben werden. Die Analyse mit dem Profiler hat ergeben, dass die Konvertierung String<->Double die meiste Zeit in Anspruch nimmt. Es sind übrigens sehr viele Messdaten, die über Jahre erfasst werden und dann ausgewertet werden. Da macht sich der Zeitunterschied zur Binärspeicherung bemerkbar, wie wir bereits getestet haben.

    Du weißt schon, dass Binärspeichern Compiler-/Plattform-/Einstellungs-/...abhängige Files erzeugt, oder ? Wenn Du also später mal diese Files wieder einlesen möchtest, hast Du gute Chancen, die Daten gar nicht mehr einlesen zu können...

    Dieses Problem haben wir diskutiert. So häufig wird sich unser System nicht ändern. Falls es dann zu einer Systemänderung kommt, sollen die Daten dann alle in einem anderen Format, beispielsweise als Plaintext gespeichert werden. Liest man diesen Plaintext im neuen System wieder ein, kann er dann wieder - mit der anderen Darstellung - binär gespeichert werden. Dies wäre dann ein einmaliger Vorgang im Gegensatz zum normalen Laden und Speichern, der durchaus häufiger auftauchen könnte.

    Grüße
    Philipp



  • OK,

    das klingt schon besser (Du fällst damit anscheinend in das verbleibende Prozent 😉 ).

    Das bedeutet also, dass Ihr ein "internes" und ein "portables" Format habt ... und es geht Dir hier um die Implementation des internen. Finde ich eine gute Lösung (solange ihr regelmäßig Eure Daten im portablen Format sichert).

    PhilippF schrieb:

    ...Dort habe ich eine Klasse TMemoryStream. Mithilfe dieser Klasse kann ich beliebige Typen einfach binär in einen Stream lesen und schreiben. Gibt es eine ähnliche Klasse in C++? ...

    Nicht, dass ich wüsste. Das Problem ist eben, dass in C++ (leider ? zum Glück ?) kein "Speicherlayout" definiert wurde....

    Mich wundert Dein unten geschilderte "Abbruch beim Lesen". Öffnest du den Stream mit binär-Flag ?
    Ich würde mal versuchen, byteweise in ein char[] einzulesen und dann den reinterpret_cast<double*>(&c[0]) darauf zu machen...

    Gruß,

    Simon2.



  • Habt ihr mal daran gedacht eine DB zu verwenden?
    z.B.
    http://www.firebirdsql.org/ (da gibt es eine embedded Version)
    http://www.sqlite.org/

    Das kann einiges vereinfachen und auch die Performance verbessern.



  • Ich weiss nicht, obs schon gepostet wurde.
    Binär könntest du (müsstest du) das etwa so machen

    double myDouble = 0.0;
    ...
    
    ofstream file("...",ios::binary);
    file.write(reinterpret_cast<char*>(&myDouble),sizeof(myDouble));
    
    // und das lesen ist ähnlich
    double myDouble
    ifstream file("...",ios::binary);
    file.read(reinterpret_cast<char*>(&myDouble),sizeof(myDouble));
    


  • Hallo,

    erst nochmal vielen Dank! Es ist echt toll, wieviel Mühe sich hier gegeben wird.

    Ich habe unser Problem jetzt mal auf ein Minimalbeispiel heruntergebrochen. Hier wird das Schreiben in einen Stream, das Kopieren in den Buffer, das Kopieren vom Buffer in den Stream und das Lesen aus dem Stream durchgeführt. Die ersten beiden Schritte sind nötig für einen Speichervorgang, die zweiten beiden für einen Ladevorgang.

    Kurz nochmal zur Erläuterung: Der Klimmzug stream<->Buffer ist nötig, weil in der Klasse, die das interne Format verwaltet mit Streams gearbeitet wird. Diese Klasse wird in unterschiedlichen Programmen verwendet. Die unterschiedlichen Programme stellen jeweils Schnittstellen zum Laden und Speichern zur Verfügung. Problematisch ist hier, dass die Schnittstelle im einen Programm über char* kommuniziert und das andere Programm über Streams.

    Zurück zur Beispielroutine: Die untenstehende Version macht genau das gewünschte. Ersetzt man jetzt die 47.11 durch die andere Zahl, die im Kommentar angegeben ist, kommt Müll heraus.

    Ich hoffe, das verdeutlicht mein Problem besser. Bin dankbar für jegliche Tipps

    Grüße
    Philipp

    P.S. Habe gesehen, dass mittlerweile noch mehr Beiträge eingegangen sind. Das geht ja echt schnell ;).

    @ihoernchen: Danke, aber das war mir bereits bekannt. Genau so speichere ich in den Stream. Probleme gibt es beim Verschieben ins char*. Eine DB scheidet aus Gründen, die nicht in meiner Hand liegen, leider aus.

    P.P.S: Den Tipp mit dem byteweisen einlesen, werde ich mal testen. Glaubst du, dass dies sehr auf die Performance gehen wird?

    void minimalTest()
    {
    	double y;
    	long long x;
    	string caption;
    
    	stringstream stream;
    	int ssize;
    
    	//Diese Werte sollen gespeichert werden
    	caption = "Testbeispiel";
    	y = 47.11; //0.751293;
    	x = 100;
    
    	//Schreiben in den Stream
    	ssize = (int)caption.length();
    	stream.write(reinterpret_cast<char *>(&ssize), sizeof(ssize));
    	stream.write(reinterpret_cast<char *>(&caption[0]), ssize);
    	stream.write(reinterpret_cast<char *>(&y), sizeof(y));
    	stream.write(reinterpret_cast<char *>(&x), sizeof(x));
    
    	//Schreiben in den Buffer
    	int size = stream.tellp();
    	char* buffer = new char[size];
    	stream.seekg(0);
    	stream.get(&buffer[0],size);
    
    	//Zurückinitialisieren
    	caption = "";
    	y = 0.0;
    	x = 0;
    
    	//Buffer -> Stream
    	stringstream stream2;
    	stream2.write(buffer, size);
    	stream2.seekg(0, ios::beg);
    
    	//Lesen aus dem Stream in die Variablen
    	stream2.read(reinterpret_cast<char *>(&ssize), sizeof(ssize));
    	caption.resize(ssize);
    	stream2.read(reinterpret_cast<char *>(&caption[0]), ssize);
    	stream2.read(reinterpret_cast<char *>(&y), sizeof(y));
    	stream2.read(reinterpret_cast<char *>(&x), sizeof(x));
    
    	//Ausgabe
    	cout << caption << endl;
    	cout << y << endl;
    	cout << x << endl;
    }
    


  • Ändere mal bitte das Schreiben in den Puffer dahin ab.

    size_t size = stream.tellp();
    char* buffer = new char[size];
    stream.clear();
    stream.seekp(0, ios::beg);
    stream.readsome(buffer,size);
    

    So ähnlich mach ich das normalerweise.



  • PhilippF schrieb:

    //Schreiben in den Buffer
    	int size = stream.tellp();
    	char* buffer = new char[size];
    	stream.seekg(0);
    	stream.get(&buffer[0],size);
    
    }
    

    Ersetzt das durch

    //Schreiben in den Buffer
        int size = stream.tellp();
        char* buffer = new char[size];
        // falsch, siehe unten
        //stream.seekg(0);
        //stream.get(&buffer[0],size);
    
        memcpy(buffer,stream.str().c_str(),size);
    

    weil http://www.cplusplus.com/reference/iostream/istream/get.html:
    istream& get (char s, streamsize n );*
    Extracts characters from the stream and stores them as a c-string into the array beginning at s. Characters are extracted until either (n - 1) characters have been extracted or the delimiting character '\n' is found. The extraction also stops if the end of file is reached in the input sequence or if an error occurs during the input operation.
    If the delimiting character is found, it is not extracted from the input sequence and remains as the next character to be extracted. Use getline if you want this character to be extracted (and discarded).
    The ending null character that signals the end of a c-string is automatically appended at the end of the content stored in s.



  • Vielen, vielen Dank! Mit memcpy funktioniert es. Die Funktion scheint da rigoroser zu sein. Jetzt wird auch die böse 0.751293 eingelesen :).



  • Deswegen hatt ich readsome vorgeschlagen, das hat die Probleme von get auch nicht. 🙂


Anmelden zum Antworten