2016-04-22 8 views
3

Bevor ich beginne, sollten Sie diesen Code:C++ mehrere Objekte in eine Datei serialisiert und deserialisiert begrenzte Anzahl von ihnen

Ein Datentransferobjekt ObjectDTO

class ObjectDTO { 

public: 
    int id; 
    string string1; 
    string string2; 
    string string3; 
    int code1; 
    vector<string> stringList1; 

private: 
    friend class boost::serialization::access; 

    template<class Archive> 
    void serialize(Archive &archive, const unsigned int version) { 
     archive & id; 
     archive & string1; 
     archive & string2; 
     archive & string3; 
     archive & code1; 
     archive & stringList1; 
    } 

Serialisierung

void OutputStreamService::writeReportsToFile(vector<ObjectDTO> objects, int filename){ 
    ofstream outputFileStream(to_string(filename)); 
    boost::archive::binary_oarchive outputArchive(outputFileStream); 
    outputArchive << objects; 
} 

Deserialisierung

vector<ObjectDTO> InputStreamService::readObjects() { 
    ifstream inputFileStream(to_string(fileNumber++)); 
    boost::archive::binary_iarchive inputArchive(inputFileStream); 
    vector<ObjectDTO> objects; 
    inputArchive >> objects; 
    return objects; 
} 

Ich verwende Boost Serialization C++ librarys, um eine vector von s zu serialisieren und es später wieder zu lesen.

nehme an i erzeugt 30GB zufälliger s und speicherte es auf die gleiche Datei

Wie ich einige von ihnen lesen kann nur erreicht Speicherlimit zu vermeiden?

Ich benutze Boost Serialisierung, weil es die einfache Weise war, die ich gefunden habe, um das erste Problem zu lösen, aber ich kann zu jeder anderen Annäherung wenn notwendig ändern!

+0

Sie lesen die Datei offenbar auf einem anderen System als dort, wo Sie sie generieren? Haben Sie das Memory-Mapping in Betracht gezogen (Boost Interprocess 'managed_mapped_file' kommt Ihnen in den Sinn)? – sehe

+0

@Sehe das ist nicht der Fall. Das Programm zeigt drei Optionen an: Erstellen und Speichern (zufällig generierte Daten), Suchen und Löschen. Jeder von ihnen muss mit vom Benutzer bereitgestellten Seitenumbrüchen (speichern Sie 1000 ObjectDTOs in 10 Dateien, suchen Sie 5 ObjectDTOs in einer Datei mit 1000). Das Hauptproblem hier ist, dass ich nicht die ganze Datei laden kann, um diese 5 ObjectDTOs zu erhalten, die ich im letzten Beispiel erwähnte ... weil in einigen Situationen die Datei größer sein kann als der Speicher, den Sie kennen? Ich werde trotzdem auf 'managed_mapped_file' schauen! –

+0

Wie können Sie es serialisieren, wenn es zu groß ist, um in den Speicher zu passen. Wenn Sie es serialisieren können, können Sie auf der gleichen Maschine im Prinzip deserialise – sehe

Antwort

0

I löste das Problem Boost-Serialisierung und Vektoren für Arrays mit einfachen alten C++ write und read auf ofstream und ifstream jeweils verwerfen.

Mein OutputStreamService writeObjectsToFile wie folgt beendet:

void OutputStreamService::writeObjectssToFile(ObjectDTO * objects, int filename){ 
     ofstream outputFileStream(to_string(filename), std::ios::binary); 
     outputFileStream.write((char *)&objects, sizeof(objects)); 
} 

Und InputStreamService mit readObjects:

ObjectDTO * InputStreamService::readObjects() { 
    ifstream inputFileStream(to_string(fileNumber++), std::ios::binary); 
    ObjectDTO objects[10]; 
    inputFileStream.read((char *)&objects, sizeof(objects)); 
    return objects; 
} 

Auf diese Weise i 10 oder jede andere ganze Zahl als die Anzahl der Objekte definieren kann ich in lesen wollen .

Um das Problem zu lösen, kann ich jetzt die ungefähre Anzahl von Objekten berechnen, die mein Speicher verarbeiten kann und dann begrenzen die Anzahl der Lesevorgänge!

Ty!

+0

1) Ihre 'ObjectDTO' Klasse ist kein POD, das wird nicht funktionieren. 2) Ihr Code oben ist auf verschiedene andere Arten gebrochen. – beerboy

+1

@Beerboy arbeitete an C++ 11 unter Linux –

1

Verwenden Sie stattdessen Google-Protokollpuffer, die CodedOutputStream-Klasse für die Serialisierung und CodedInputStream für die Deserialisierung.

Eine der CodedOutputStream-Methoden ist WriteVarint32, mit der eine Zahl geschrieben werden kann, die als Index im Stream verwendet werden kann.

In CodeInputStream gibt es entsprechende ReadVarint32 Methode, z.

Serialisierung:

char text[[]] = "Hello world!"; 
coded_output->WriteVarint32(strlen(text)); 
coded_output->WriteRaw(text, strlen(text)); 

Deserialisierung:

uint32 size; 
coded_input->ReadVarint32(&size); 

char* text = new char[size + 1]; 
coded_input->ReadRaw(buffer, size); 

Die letzte Zeile können Sie den Inhalt von serialisierten Stream lesen von bestimmten Index begonnen.

Hier sind meine zwei Methoden zum Serialisieren/Deserialisieren von Streams mit gegebener Länge am Anfang.

template < class T> 
void TProtoBufSerializer::SerializeImplementation(const T& protoBuf, std::vector<char>& buffer) 
{ 
    int bufLength = protoBuf.ByteSize() + google::protobuf::io::CodedOutputStream::VarintSize32(protoBuf.ByteSize()); 
    buffer.resize(bufLength); 

    google::protobuf::io::ArrayOutputStream arrayOutput(&buffer[0], bufLength); 
    google::protobuf::io::CodedOutputStream codedOutput(&arrayOutput); 

    codedOutput.WriteVarint32(protoBuf.ByteSize()); 
    protoBuf.SerializeToCodedStream(&codedOutput);  
} 

template < class T> 
bool TProtoBufSerializer::DeSerializeImplementation(std::vector<char>& buffer, T& protoBuf) 
{ 
    bool deserialized = false; 

    google::protobuf::io::ArrayInputStream arrayInput(&buffer[0],buffer.size()); 
    google::protobuf::io::CodedInputStream codedInput(&arrayInput); 

    unsigned int object_size; 
    bool header_readed = codedInput.ReadVarint32(&object_size); 

    if(header_readed && object_size > 0) 
    { 
     if(buffer.size() >= codedInput.CurrentPosition() + object_size) 
     { 
      google::protobuf::io::CodedInputStream::Limit limit = codedInput.PushLimit(object_size); 

      if(protoBuf.ParseFromCodedStream(&codedInput)) 
      { 
       std::vector<char>::iterator it = buffer.begin(); 
       std::advance(it,codedInput.CurrentPosition()); 
       std::move(it,buffer.end(),buffer.begin()); 
       buffer.resize(buffer.size() - codedInput.CurrentPosition()); 
       deserialized = true; 
      } 
      else 
      { 
       throw TProtoBufSerializerPayloadException(); 
      } 
      codedInput.PopLimit(limit); 
     } 
    } 
    else 
    { 
     //varint32 which is used in header is at the most 5 bytes long, 
     //if given buffer is 5 bytes or more long and header still cannot be decoded - raise exception 
     if(buffer.size() >= 5) 
     { 
      throw TProtoBufSerializerHeaderException(); 
     } 
    } 
    return deserialized; 
} 
+0

Was ist das für die Syntax von [[]] 'und' [[] size + 1] '? Was genau macht das, was 'std :: fstream' nicht tut? – sehe

+0

Entschuldigung Ich habe es kopiert und eingefügt von hier: https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.coded_stream#classes-in-this-file, fstream beschäftigt sich mit Datei, während dies über (De) Serialisierung - Putting der Inhalt der Datei in C++ Objekte –

+0

Hallo @MarekWaszkiewicz, ich endete mit einem nativen Ansatz, aber danke für Ihre Answear und hoffe, es kann anderen Zuschauern helfen! –