двоичные файлы — C ++ чтение двоичных файлов

Я пытаюсь сохранить объекты, включая векторы объектов, в двоичном файле.

Вот немного загрузки из файла кода:

template <class T> void read(T* obj,std::ifstream * file) {
file->read((char*)(obj),sizeof(*obj));
file->seekg(int(file->tellg())+sizeof(*obj));
}

void read_db(DB* obj,std::ifstream * file) {
read<DB>(obj,file);
for(int index = 0;index < obj->Arrays.size();index++) {
std::cin.get(); //debugging
obj->Arrays[0].Name = "hi"; //debugging
std::cin.get(); //debugging
std::cout << obj->Arrays[0].Name;
read<DB_ARRAY>(&obj->Arrays[index],file);
for(int row_index = 0;row_index < obj->Arrays[index].Rows.size();row_index++) {
read<DB_ROW>(&obj->Arrays[index].Rows[row_index],file);
for(int int_index = 0;int_index < obj->Arrays[index].Rows[row_index].i_Values.size();int_index++) {
read<DB_VALUE<int>>(&obj->Arrays[index].Rows[row_index].i_Values[int_index],file);
}
}
}
}

А вот и классы DB / DB_ARRAY

class DB {
public:
std::string Name;
std::vector<DB_ARRAY> Arrays;
DB_ARRAY * operator[](std::string);
DB_ARRAY * Create(std::string);
};
class DB_ARRAY {
public:
DB* Parent;
std::string Name;
std::vector<DB_ROW> Rows;
DB_ROW * operator[](int);
DB_ROW * Create();
DB_ARRAY(DB*,std::string);
DB_ARRAY();
};

Так что теперь первый аргумент функции read_db будет иметь правильные значения, а векторный массив Arrays для объекта будет иметь правильный размер. Однако, если я индексирую любое значение любого объекта из obj-> Arrays, это вызовет исключение нарушения доступа.

std::cout << obj->Arrays[0].Name; // error
std::cout << &obj->Arrays[0]; // no error

Последний всегда печатает один и тот же адрес, поэтому, когда я сохраняю объект, приведенный к типу char *, он тоже сохраняет его адрес?

1

Решение

Как указывали различные комментаторы, вы не можете просто сериализовать (не POD) объект, сохранив / восстановив его память.

Обычный способ реализации сериализации — реализовать интерфейс сериализации на классах. Что-то вроде этого:

struct ISerializable {
virtual std::ostream& save(std::ostream& os) const = 0;
virtual std::istream& load(std::istream& is) = 0;
};

Затем вы реализуете этот интерфейс в ваших сериализуемых классах, рекурсивно вызывая save а также load на любых членах, ссылающихся на другие сериализуемые классы, и выписывающих любых членов POD. Например.:

class DB_ARRAY : public ISerializable {
public:
DB* Parent;
std::string Name;
std::vector<DB_ROW> Rows;
DB_ROW * operator[](int);
DB_ROW * Create();
DB_ARRAY(DB*,std::string);
DB_ARRAY();

virtual std::ostream& save(std::ostream& os) const
{
// serialize out members
return os;
}

virtual std::istream& load(std::istream& is)
{
// unserialize members
return os;
}
};

Как count0 указал, повышение :: сериализации это также отличная отправная точка.

0

Другие решения

Каков формат двоичных данных в файле? Пока вы не укажете
что мы не можем сказать вам, как это написать. В основном, вы должны указать
формат для всех ваших типов данных (кроме char), затем напишите код
записать этот формат, побайтово (или сгенерировать его в буфер);
и с другой стороны, чтобы прочитать его побайтово и восстановить его.
Стандарт C ++ ничего не говорит (или очень мало) о размере и
представление типов данных, Кроме тот sizeof(char) должно быть
1, и это unsigned char должно быть чисто двоичное представление над
все биты. И на машинах у меня есть доступ сегодня (Sun Sparc и
ПК), только типы символов имеют общее представление. Что касается
чем более сложные типы, тем память используется в представлении значения
может даже не быть смежным: побитовое представление
std::vectorНапример, обычно это три указателя, причем
Значения в векторе находятся где-то еще полностью.

Функции istream::read а также ostream::write являются
предназначен для чтения данных в буфер для ручного анализа и записи
предварительно отформатированный буфер. Тот факт, что вам нужно использовать
reinterpret_cast использовать их иначе должно быть хорошим показателем
что это не сработает.

0