15 Stimmen

Schreiben und Lesen von Klassenobjekten in und aus Binärdateien

Ich versuche, in C++ ein Objekt einer Klasse in eine Binärdatei zu schreiben und daraus zu lesen. Ich möchte die Datenelemente nicht einzeln schreiben, sondern das gesamte Objekt auf einmal. Für ein einfaches Beispiel:

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;  
}

Die laufende Ausgabe zeigt jedoch, dass der Wert von mm.i, der angeblich in die Binärdatei geschrieben wurde, nicht korrekt gelesen und mm2.i zugewiesen wird

$ ./main   
3  
2  
2  

Was ist also falsch daran?

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

11voto

R Samuel Klatchko Punkte 72641

Die Daten werden gepuffert, so dass sie die Datei noch nicht erreicht haben, wenn Sie sie lesen wollen. Da Sie zwei verschiedene Objekte verwenden, um auf die Eingangs- und Ausgangsdatei zu verweisen, hat das Betriebssystem keine Ahnung, wie sie zusammenhängen.

Sie müssen entweder die Datei leeren:

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

oder schließen Sie die Datei (was einen impliziten Flush auslöst):

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

Sie können die Datei auch schließen, indem Sie das Objekt aus dem Anwendungsbereich entfernen:

int main()
{
    myc mm(3);

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

    ...
}

0 Stimmen

Danke! Ist es möglich, in C++ ein einziges Objekt sowohl für das Schreiben als auch für das Lesen von Dateien zu definieren? Ich erinnere mich, dass dies in C möglich ist.

0 Stimmen

@Tim. Ja, Sie können einen Dateistrom zum Lesen und Schreiben öffnen lassen.

0 Stimmen

Meiner Meinung nach ist die Antwort von Yann Ramin viel nützlicher. Er erklärt diese Flushing-Idee, und zeigt auch einen besseren Weg mit Boost.

9voto

Yann Ramin Punkte 32375

Das Dumping von Rohdaten ist in mehrfacher Hinsicht eine schreckliche Idee. Dies wird noch schlimmer, wenn Sie Zeigerdaten hinzufügen.

Ein Vorschlag wäre die Verwendung von Boost.Serialisierung was ein wesentlich robusteres Datendumping ermöglicht.

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

2voto

Ich schließe mich der Meinung an: "Sie sollten das nicht tun". Wenn Sie ausdrucken sizeof(myc) im obigen Code ist es wahrscheinlich 4, wie Sie erwarten würden... ABER versuchen Sie, read und write auf virtuell zu ändern. Wenn ich das getan habe, wird die Größe als 16 ausgegeben. Diese 12 Bytes sind interne Eingeweide mit sensiblen Werten - sie auszulagern und dann wieder einzulesen wäre so, als würde man erwarten, dass ein Zeigerwert noch gut ist, wenn man ihn schreibt und wieder lädt.

Wenn Sie die Serialisierung umgehen und den C++-Objektspeicher direkt auf der Festplatte abbilden möchten, gibt es Möglichkeiten, dies zu erreichen. Aber es gibt Regeln und es ist nichts für schwache Nerven. Siehe POST++ (Persistente Objektspeicherung für C++) als Beispiel.

Ich füge hinzu, dass Sie nicht geprüft haben, ob die fail() o eof() Status. Wenn Sie das getan hätten, wüssten Sie, dass Sie die fstream-API missbrauchen. Versuchen Sie es erneut 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.

1voto

Mein C++ ist ziemlich rostig und kaum getestet, aber vielleicht möchten Sie einen Blick auf Serialisierung und Unserialisierung werfen. FAQ

0voto

jfo420 Punkte 1

Ich habe etwas Ähnliches gemacht mit output.write((char*)&obj, sizeof(obj)) wobei obj eine Instanz Ihrer Klasse ist. Sie können diese Schleife verwenden, wenn Sie die Daten stattdessen in das Objekt schreiben wollen, was im Allgemeinen der Fall ist, da die Mitglieder lesbar sein müssen, richtig?

Dasselbe gilt für das Lesen mit der Lesefunktion. Aber wenn Sie dynamische Zuordnung zu tun haben, dann mit diesen Daten, müssen Sie es zu behandeln.

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