speichern von einem Vektor von Objekten auf der Festplatte



  • Sehr geehrte Community,

    ich habe eine simple Frage zu einem wohl komplizierten Problem.

    Ich möchte ein paar Objekte die in einem Vektor gebunden sind auf der Festplatte speichern. Was gibt es da für Möglichkeiten? Am liebsten wäre es mir, wenn ich all die Daten auf einem anderen Rechner wieder einlesen könnte. Ist so etwas prinzipiel möglich?

    Vielen Dank!



  • Ja, Stichwort Serialization.



  • Jepp, habe kurz quer gelesen.

    Welche Bib empfehlt ihr? Boost?

    Danke!



  • Ingeborg schrieb:

    Jepp, habe kurz quer gelesen.

    Welche Bib empfehlt ihr? Boost?

    Danke!

    Boost ist sicherlich nicht verkehrt. In einfachen Fällen kann man so etwas aber auch recht einfach selber schreiben. Dann kommt man ohne zusätzliche Bibliothek aus.



  • Ingeborg schrieb:

    Am liebsten wäre es mir, wenn ich all die Daten auf einem anderen Rechner wieder einlesen könnte. Ist so etwas prinzipiel möglich?

    Dann musst das Ganze natürlich portabel sein. Dafür bietet sich

    an. Bei Boost Serialization darauf achten, dass du text archives nimmst. Aber ich denke auch

    TNA schrieb:

    In einfachen Fällen kann man so etwas aber auch recht einfach selber schreiben.



  • Ingeborg schrieb:

    ich habe eine simple Frage zu einem wohl komplizierten Problem.

    Ich möchte ein paar Objekte die in einem Vektor gebunden sind auf der Festplatte speichern. Was gibt es da für Möglichkeiten? Am liebsten wäre es mir, wenn ich all die Daten auf einem anderen Rechner wieder einlesen könnte. Ist so etwas prinzipiel möglich?

    Das Problem ist nicht kompliziert, wenn die Objekte, die Du speichern möchtest, nicht kompliziert sind.

    Kannst Du mal alle Member der Klasse so eines Objekts hier posten; dass man sieht, was das für Typen sind.
    Normalerweise brauchst Du dafür gar keine Bibliothek.



  • Hi!

    Danke bis hierher.

    Es handelt sich genauer um einen Vector mit diesen struct als Vektorgrößen:

    struct RoiDbStruct
    {
        QString name;
        Mat ;
        vector<Vec2f>;
        vector<Vec2i>;
        vector<Vec3f>;
        vector<Vec4i>;
        vector< vector< Point> >;
        vector<KeyPoint>;
        Mat ;
        vector<KeyPoint>;
        Mat;
        vector<KeyPoint>;  
        Mat ;
        vector<KeyPoint> ; 
    };
    

    Mat und KeyPoint sind Klassen von OpenCV.
    Einfach ist dieses Struct nicht.
    Sie ist einfach dahingehend, dass es keine direkt vererbten Klassen sind.
    Am liebsten wäre es mir natürlich wenn ich den Structvektor so wie er ist speichern könnte und ihn auf einer anderen Plattform wieder lesbar machen kann... Vll gibt es ja was von Qt5 (meine IDE)?

    Danke nochmal!



  • Ingeborg schrieb:

    Vll gibt es ja was von Qt5 (meine IDE)?

    Qt bietet die Möglichkeit, eigene Datentypen zu serialisieren. Ich weiß nicht, wie das bei fremden Klassen ist.



  • In Qt läuft sowas z. Bsp. über QDataStream. Diese Klasse bietet portables binäres lesen und schreiben für viele Datentypen (C++ Standard und viele Qt Klassen). Bei eigenen Klasse muss man sich die dafür notwendigen Funktionen selber schreiben.
    Ein bisschen was dazu steht auch in der Hilfe zu QDataStream.



  • Ingeborg schrieb:

    Hi!

    Danke bis hierher.

    Es handelt sich genauer um einen Vector mit diesen struct als Vektorgrößen:

    struct RoiDbStruct
    {
        QString name;
        Mat ;
        vector<Vec2f>;
        vector<Vec2i>;
        vector<Vec3f>;
        vector<Vec4i>;
        vector< vector< Point> >;
        vector<KeyPoint>;
        Mat ;
        vector<KeyPoint>;
        Mat;
        vector<KeyPoint>;  
        Mat ;
        vector<KeyPoint> ; 
    };
    

    Mat und KeyPoint sind Klassen von OpenCV.
    Einfach ist dieses Struct nicht.
    Sie ist einfach dahingehend, dass es keine direkt vererbten Klassen sind.
    Am liebsten wäre es mir natürlich wenn ich den Structvektor so wie er ist speichern könnte und ihn auf einer anderen Plattform wieder lesbar machen kann... Vll gibt es ja was von Qt5 (meine IDE)?

    Danke nochmal!

    Hallo Ingeborg,

    jetzt hat Dir noch keiner verraten, wie es geht - oder?
    Die Grundidee ist es, für jeden Typ (struct oder class) einen sogenannten Streamingoperator zu schreiben. Ziel ist es alles in texttueller Form zu speichern und zu lesen. Das mag nicht die schnellste Form sein, aber erstens ist man kompatibel mit allen möglichen anderen Systemen und zum anderen kann man mit Hilfe eines einfachen Editors die Ausgabe kontrollieren.

    Für die Struktur RoiDbStruct heißt das:

    std::ostream& operator<<( std::ostream& out, const RoiDbStruct& obj );
    

    für das Schreiben und

    std::istream& operator>>( std::istream& in, RoiDbStruct& obj );
    

    für das Lesen.

    Dann wird folgendes möglich:

    RoiDbStruct obj;
        // obj mit Informationen füllen
        std::ofstream output( "SaveRoiDbStruct.txt" );
        if( output << obj )
            std::cout << "Speichern Ok" << std::endl;
    

    .. und umgekehrt das Lesen:

    RoiDbStruct obj;
        std::ifstream input( "SaveRoiDbStruct.txt" );
        if( input >> obj )
            std::cout << "Laden Ok" << std::endl;
    

    wie werden diese Streamingoperatoren implementiert - nun indem 'einfach' alle Member abgespeichert, bzw. gelesen werden:

    struct RoiDbStruct
    {
        QString name;
        Mat mat1;
        vector<Vec2f> vec1;
        vector<Vec2i> vec2;
        vector<Vec3f> vec3;
        vector<Vec4i> vec4;
        vector< vector< Point> > points;
        vector<KeyPoint> keypoints1;
        Mat mat2;
        vector<KeyPoint> keypoints2;
        Mat mat3;
        vector<KeyPoint> keypoints3;
        Mat mat4;
        vector<KeyPoint> keypoints4; 
    };
    
    std::istream& operator>>( std::istream& in, RoiDbStruct& obj )
    {
        in >> obj.name >> obj.mat1 >> obj.vec1 >> obj.vec2 ... // usw.
        return in;
    }
    

    Die Ausgabe entsprechend.

    Damit das funktioniert ist für jeden Membertypen ebenso ein Streamingoperatorenpaar zu schreiben. Für QString ist das noch relativ einfach, wenn ich mal annehmen, dass dort nur ASCII-Zeichen hinterlegt sind, und kein Zeilenumbruch (EOL).

    Schreiben:

    std::ostream& operator<<( std::ostream& out, const QString& s )
    {
        return out << s.toStdString() << "\n"; // EOL beendet den String
    }
    

    Lesen:

    std::istream& operator>>( std::istream& in, QString& s )
    {
        std::string line;
        if( std::getline( in, line ) ) // Zeile gelesen?
            s = line.c_str();
        return in;
    }
    

    Den Typ Mat lasse ich hier mal weg - Vec2f und die weiteren Vec*-typen sollte einfach sein:

    std::ostream& operator<<( std::ostream& out, const Vec2f& v )
    {
        return out << v.x << " " << v.y;
    }
    std::istream& operator>>( std::istream& in, Vec2f& v )
    {
        float x, y;
        if( in >> x >> y )
            v = Vec2f( x, y );
        return in;
    }
    

    Einen std::vector<T> abzuspeichern geht im Prinzip genauso, nur dass Du Dich um die Anzahl der Elemente kümmern musst. Das könnte allgemein so aussehen:

    template< typename T >
    std::ostream& operator<<( std::ostream& out, const std::vector<T>& v )
    {
        out << v.size() << "\n"; // die Anzahl
        for( auto i = begin(v); i != end(v); ++i )
            out << *i << "\n";
        return out;
    }
    template< typename T >
    std::istream& operator>>( std::istream& in, std::vector<T>& v )
    {
        std::vector<T>::size_type n;
        if( in >> n ) // Anzahl der Elemente
        {
            std::vector<T> result;
            result.reserve(n);
            T obj;
            for( std::vector<T>::size_type i=0; i<n && in >> obj; ++i )
                result.push_back( obj );
            if( in )
                v = std::move( result );       
        }
    }
    

    usw. - wenn man das Prinzip verstanden hat, ist es mehr eine Fleißarbeit, als ein Problem.
    Wenn Du mehr wissen möchtest, dann frage noch mal nach.

    Gruß
    Werner


  • Mod

    Wenn du schon C++11 verwendest, Werner, warum nicht gleich so:

    for( auto i = begin(v); i ! end(v); ++i )
        out << *i << "\n";
    // =>
    for( auto const& i : v )
        out << i << "\n";
    

    Für QString ist das noch relativ einfach, wenn ich mal annehmen, dass dort nur ASCII-Zeichen hinterlegt sind, und kein Zeilenumbruch (EOL).

    EOL ist auch Teil von ASCII (LF, CR, CRLF)... (?)
    Die Annahme ist außerdem nicht zu rechtfertigen, wenn man das ganze allgemein implementieren will, wie du gezeigt hast. Da müsste man eine allgemeine Funktion für Container implementieren, die es macht wie du für vector in deinem Post.



  • Arcoth schrieb:

    Wenn du schon C++11 verwendest, Werner, warum nicht gleich so:

    .. weil mein Compiler das nicht kann 😉

    Arcoth schrieb:

    Für QString ist das noch relativ einfach, wenn ich mal annehmen, dass dort nur ASCII-Zeichen hinterlegt sind, und kein Zeilenumbruch (EOL).

    EOL ist auch Teil von ASCII (LF, CR, CRLF)... (?)
    Die Annahme ist außerdem nicht zu rechtfertigen, wenn man das ganze allgemein implementieren will, wie du gezeigt hast. Da müsste man eine allgemeine Funktion für Container implementieren, die es macht wie du für vector in deinem Post.

    ist ja alles richtig, was Du sagst, aber ich wollte es nicht zu kompliziert machen.


  • Mod

    ist ja alles richtig, was Du sagst, aber ich wollte es nicht zu kompliziert machen.

    Verständlich. 👍

    .. weil mein Compiler das nicht kann

    Dieser ver******* VC++ 😡



  • Arcoth schrieb:

    Dieser ver******* VC++ 😡

    beruhig dich, brauner.



  • Oh vielen Dank,

    ich dachte, dass ebenjene in und outstreamen eben nicht funktioniert. Vielen Dank! Das erleichtert mir einiges.

    Grüße!
    Inge



  • otze schrieb:

    Arcoth schrieb:

    Dieser ver******* VC++ 😡

    beruhig dich, brauner.

    Also mein Visual Studio kann sowohl Range-based for Schleifen als auch einige andere C++11-Features...

    Kann doch sein, dass Werner einen alten GCC oder so benutzt hat. Wieso immer gleich gegen MSVC?


Log in to reply