Запись и чтение объекта класса в двоичный файл и из него

Я пытаюсь написать и прочитать объект класса в и из двоичного файла в С++. Я хочу не писать элемент данных отдельно, но писать весь объект за один раз. Для простого примера:

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

Однако работающий вывод показывает, что значение mm.i, предположительно записанное в двоичный файл, не читается и не назначено на mm2.i правильно

$ ./main   
3  
2  
2  

И что с этим не так?

Что я должен знать, когда вообще пишу или читаю объект класса в двоичный файл или из него?

Ответы

Ответ 1

Данные буферизуются, поэтому на самом деле он не достиг файла, когда вы читаете его. Поскольку вы используете два разных объекта для ссылки на файл ввода/вывода, ОС не знает, как они связаны.

Вам нужно либо сбросить файл:

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

или закройте файл (который делает неявный флеш):

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

Вы также можете закрыть файл, если объект выходит за рамки:

int main()
{
    myc mm(3);

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

    ...
}

Ответ 2

Сбрасывание необработанных данных - ужасная идея, с разных точек зрения. Это будет ухудшаться, если вы добавите данные указателя.

Одно из предложений заключалось бы в использовании Boost.Serialization, который позволяет гораздо более надежный сброс данных.

Основная проблема заключается в том, что файл не содержит содержимого из-за буферизации fstream. Закройте или закройте файл.

Ответ 3

Я буду эхом "вы не должны этого делать". Если вы напечатаете sizeof(myc) в приведенном выше коде, возможно, 4, как и следовало ожидать... НО попробуйте изменить чтение и запись на виртуальные. Когда я это сделал, он печатает размер как 16. Эти 12 байтов являются внутренними кишками с чувствительными значениями &mdash и сохраняют их, а затем считывают их обратно, это будет похоже на то, что значение указателя будет по-прежнему хорошим, если вы его написали и загрузили это снова.

Если вы хотите обойти сериализацию и отобразить память объекта С++ непосредственно на диск, есть способы взломать это. Но правила задействованы, и это не для слабонервных. В качестве примера см. POST ++ (Persistent Object Storage для С++).

Я добавлю, что вы не проверяли статус fail() или eof(). Если бы вы знали, что используете API-интерфейс fstream. Попробуйте еще раз:

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

... и посмотрим, что произойдет.

Ответ 4

Мой С++ довольно ржавчина и сильно недооценена, но вы можете взглянуть на Сериализацию и Unserialization. FAQ