Запись и чтение объекта класса в двоичный файл и из него - PullRequest
14 голосов
/ 12 января 2010

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

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  

Так что с ним не так?

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

Ответы [ 4 ]

11 голосов
/ 12 января 2010

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

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

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

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

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

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

int main()
{
    myc mm(3);

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

    ...
}
9 голосов
/ 12 января 2010

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

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

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

2 голосов
/ 12 января 2010

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

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

Я добавлю, что вы не проверяли статус 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;
}

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

1 голос
/ 12 января 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...