9 Stimmen

Boost Serialisierung mehrerer Objekte

Ich serialisiere eine Klasse mit boost unter Verwendung von binary. Ich verwende ios::append, um mehrere Objekte an diese Datei anzuhängen. Wie gehe ich vor, um alle gespeicherten Objekte abzurufen?

Hier ist meine Testklasse, die eine mehrfache Serialisierung versucht und sie abruft. Ich habe den Fehlerpunkt kommentiert, an dem ich keine korrekten Daten erhalte.

using namespace std;
 class Data {
 public:
double get_latitude() const {
    return _latitude;
}

double get_longitude() const {
    return _longitude;
}

void set_latitude(double _latitude) {
    this->_latitude = _latitude;
}

void set_longitude(double _longitude) {
    this->_longitude = _longitude;
}
private:
double _latitude;
double _longitude;
friend class boost::serialization::access;
// When the class Archive corresponds to an output archive, the
// & operator is defined similar to <<.  Likewise, when the class Archive
// is a type of input archive the & operator is defined similar to >>.
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
    ar & _latitude;
    ar & _longitude;
}
};

class DataTest: public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE( DataTest);
CPPUNIT_TEST(testMultipleSaveData);
CPPUNIT_TEST_SUITE_END();

public:

void testMultipleSaveData() {
    Data data;
    data.set_latitude(1.0);
    data.set_longitude(2.0);
    saveData(data);
    Data secondData;
    secondData.set_latitude(5.0);
    secondData.set_longitude(6.0);
    saveData(secondData);
    Data returnData;
    Data return2Data;
    {
        // create and open an archive for input
        std::ifstream ifs("data.dat", ios::binary);
        boost::archive::binary_iarchive ia(ifs);
        // read class state from archive
        ia >> returnData;
        ia >> return2Data;
        // archive and stream closed when destructors are called
    }
    CPPUNIT_ASSERT_EQUAL(data.get_latitude(), returnData.get_latitude());
    CPPUNIT_ASSERT_EQUAL(data.get_longitude(), returnData.get_longitude());
    //Failure on next line
    CPPUNIT_ASSERT_EQUAL(secondData.get_latitude(), return2Data.get_latitude());
    CPPUNIT_ASSERT_EQUAL(secondData.get_longitude(), return2Data.get_longitude());
}

void saveData(Data data) {
    std::ofstream ofs("data.dat", ios::binary | ios::app);
    boost::archive::binary_oarchive oa(ofs);
    oa << data;
}

 };
 CPPUNIT_TEST_SUITE_REGISTRATION( DataTest);

8voto

Andriy Tylychko Punkte 15609

Ich habe beschlossen, eine weitere Antwort hinzuzufügen, um ein völliges Durcheinander zu vermeiden.

Ihr Problem ist, dass Sie in separate Instanzen von boost::archive::binary_oarchive . Boost-Archiv speichert einige interne Informationen am Anfang der Datei (ich nenne es nicht Header, weil Boost-Serialisierung hat einen separaten Header, um die Versionsnummer zu speichern), und Sie erhalten zwei Kopien dieser Informationen, am Anfang der Datei und zwischen Ihren Datenserialisierungen.

Boost-Archiv wurde nicht für eine solche Verwendung konzipiert. Selbst die Angabe von boost::archive::no_header wie in:

boost::archive::text_oarchive oa(ofs, boost::archive::no_header);

hilft nicht, da diese Option einen anderen Header konfiguriert, der die Versionsnummer enthält. Sie müssen in dieselbe Instanz von Boost-Archiv .

3voto

Andriy Tylychko Punkte 15609

1) Wenn die Anzahl der gespeicherten Objekte konstant ist, laden Sie alle Objekte in der gleichen Reihenfolge, in der Sie sie gespeichert haben:

Speicherung:

std::ofstream ofs(FILENAME, ios::app);
boost::archive::text_oarchive oa(ofs);
oa << data1 << data2 << ... << data_n;

Laden:

std::ifstream ifs(FILENAME);
boost::archive::text_iarchive ia(ifs);
ia >> data1 >> data2 >> ... >> data_n;

2) wenn die Anzahl der gespeicherten Objekte variieren kann - serialisieren Sie die Anzahl:

Speicherung:

std::ofstream ofs(FILENAME, ios::app);
boost::archive::text_oarchive oa(ofs);
oa << number_of_objects;
for (size_t i = 0; i != number_of_objects; ++i)
    oa << data[i];

Laden:

std::ifstream ifs(FILENAME);
boost::archive::text_iarchive ia(ifs);
size_t number_of_objects;
ia >> number_of_objects;
// allocate number_of_objects objects
for (size_t i = 0; i != number_of_objects; ++i)
    ia >> data[i];

[EDIT] unter Berücksichtigung Ihrer bearbeiteten Frage:
Zunächst einmal verwenden Sie binary_archive mit Textmodus-Dateien! Sie müssen die Datei (sowohl zum Lesen als auch zum Schreiben) mit std::ios::binary flag öffnen. Dies ist ein Fehler und kann ein Grund für Ihr Problem sein ("kann sein", weil wir Ihre genaue Serialisierungsimplementierung nicht sehen).

Ich kann Ihren Code nicht kompilieren, weil es unvollständig ist. Versuchen Sie, einfache Klasse mit Serialisierung und speichern/laden 2 Objekte auf diesem einfachen Beispiel zu implementieren, um leicht zu finden, was falsch mit komplizierteren Fällen

[EDIT2] haben Sie die binary_archive von Boost.Serialisierung Beispiele? Wenn ja, beachten Sie, dass es nicht portabel ist, ich weiß nicht, ob das für Sie wichtig ist.

1voto

Edward Strange Punkte 39597

Wenn Sie mehr als eine lesen wollen, sagen Sie dem Programm, dass es mehr als eine laden soll. Die Serialisierung kann nur dann mehrere Objekte laden, wenn Sie ihr dies entweder explizit oder durch Serialisierung eines Containers von Objekten mitgeteilt haben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X