2010-01-12 11 views
13

Ich versuche zu schreiben und lesen Objekt der Klasse in und aus Binärdatei in C++. Ich möchte das Datenelement nicht einzeln schreiben, sondern das gesamte Objekt auf einmal schreiben. Ein einfaches Beispiel:Schreiben und lesen Objekt der Klasse in und aus Binärdatei

class MyClass { 
public: 
    int i; 

    MyClass(int n) : i(n) {} 
    MyClass() {} 

    void read(ifstream *in) { in->read((char *) this, sizeof(MyClass)); } 
    void write(ofstream *out){ out->write((char *) this, sizeof(MyClass));} 
}; 

int main(int argc, char * argv[]) { 
    ofstream out("/tmp/output"); 
    ifstream in("/tmp/output"); 

    MyClass mm(3); 
    cout<< mm.i << endl; 
    mm.write(&out); 

    MyClass mm2(2); 
    cout<< mm2.i << endl; 
    mm2.read(&in); 
    cout<< mm2.i << endl; 

    return 0; 
} 

jedoch die laufende Ausgabe zeigt, dass der Wert von mm.i angeblich auf die binäre Datei geschrieben wird gelesen und

$ ./main 
3 
2 
2 

Also, was ist falsch mm2.i nicht richtig zugewiesen damit?

Was soll ich beachten, wenn ich generell ein Objekt einer Klasse in eine Binärdatei schreibe oder lese?

Antwort

11

Die Daten werden gepuffert, so dass sie die Datei nicht wirklich erreicht haben, wenn Sie sie lesen. Da Sie zwei verschiedene Objekte verwenden, um auf die In/Out-Datei zu verweisen, hat das Betriebssystem keine Ahnung, wie sie miteinander verwandt sind.

Sie müssen entweder die Datei bündig:

mm.write(&out); 
out.flush() 

oder schließen Sie die Datei (was tut eine implizite Flush):

mm.write(&out); 
out.close() 

Sie die Datei auch das Objekt schließen kann aus, indem gehen of scope:

int main() 
{ 
    myc mm(3); 

    { 
     ofstream out("/tmp/output"); 
     mm.write(&out); 
    } 

    ... 
} 
+0

Danke! Ist es möglich, ein einzelnes Objekt zum Schreiben und Lesen von Dateien in C++ zu definieren? Ich erinnere mich, dass es in C. möglich ist. – Tim

+0

@Tim.YEs können Sie einen Datei-Stream zum Lesen und Schreiben geöffnet haben. –

+0

Meiner Meinung nach ist Yann Ramins Antwort viel nützlicher. Er erklärt diese Spülungsidee und zeigt auch einen besseren Weg mit Boost. – MeM

1

Mein C++ ist ziemlich Rost und stark unter-getestet, aber Sie sollten sich Serialisierung und UNSialisierung ansehen. FAQ

9

Dumping Rohdaten ist eine schreckliche Idee, aus verschiedenen Blickwinkeln. Dies wird noch schlimmer, wenn Sie Zeigerdaten hinzufügen.

Ein Vorschlag würde sein, Boost.Serialization zu verwenden, der weit robusteres data dumping ermöglicht.

Ihr Hauptproblem ist, dass die Datei den Inhalt aufgrund der fstream-Pufferung noch nicht enthält. Schließen oder leeren Sie die Datei.

2

Ich werde Echo "Sie sollten dies nicht tun". Wenn Sie sizeof(myc) im obigen Code ausdrucken, ist es wahrscheinlich 4, wie Sie erwarten würden ... ABER versuchen Sie, lesen und schreiben, um virtuell zu sein. Wenn ich dies tat, druckt es die Größe als 16 aus. Diese 12 Bytes sind interne Eingeweide mit sensitiven Werten — und sie zu speichern und dann wieder einzulesen wäre, als würde man erwarten, dass ein Zeigerwert immer noch gut ist, wenn Sie ihn geschrieben und geladen haben es wieder.

Wenn Sie die Serialisierung umgehen und den C++ - Objektspeicher direkt auf die Festplatte abbilden möchten, gibt es Möglichkeiten, dies zu hacken. Aber Regeln sind beteiligt und es ist nichts für schwache Nerven. Siehe POST++ (Persistent Object Storage for C++) als ein Beispiel.

Ich füge hinzu, dass Sie den fail() oder eof() Status nicht überprüft haben. Wenn Sie hätten, hätten Sie gewusst, dass Sie die fstream-API missbraucht haben. Versuchen Sie es noch einmal mit:

void read(ifstream *in) { 
    in->read((char *) this, sizeof(myc)); 
    if (in->fail()) 
     cout << "read failed" << endl; 
} 
void write(ofstream *out){ 
    out->write((char *) this, sizeof(myc)); 
    if (out->fail()) 
     cout << "write failed" << endl; 
} 

... und sehen, was passiert.