Запись и чтение объекта класса в двоичный файл и из него
Я пытаюсь написать и прочитать объект класса в и из двоичного файла в С++. Я хочу не писать элемент данных отдельно, но писать весь объект за один раз. Для простого примера:
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