Вектор сериализации и десериализации в двоичном формате - PullRequest
4 голосов
/ 09 августа 2010

У меня проблемы с попыткой сериализации вектора (std :: vector) в двоичный формат, а затем корректной десериализации его и возможности чтения данных. Это мой первый раз, когда я использую двоичный формат (я использовал ASCII, но теперь это стало слишком сложно использовать), поэтому я начинаю с простого только с использованием целого вектора.

Всякий раз, когда я читаю данные обратно, вектор всегда имеет правильную длину, но данные либо 0, либо неопределенные, либо случайные.

class Example  
{  
public:  
    std::vector<int> val;  
};

WRITE

Example example = Example();  
example.val.push_back(10);  
size_t size = sizeof BinaryExample + (sizeof(int) * example.val.size()); 

std::fstream file ("Levels/example.sld", std::ios::out | std::ios::binary);

if (file.is_open())  
{  
    file.seekg(0);  
    file.write((char*)&example, size);  
    file.close();  
}

ЧИТАЙТЕ:

BinaryExample example = BinaryExample();

std::ifstream::pos_type size;  
std::ifstream file ("Levels/example.sld", std::ios::in | std::ios::binary | std::ios::ate);

if (file.is_open())  
{   
    size = file.tellg();

    file.seekg(0, std::ios::beg);
    file.read((char*)&example, size);
    file.close();
}

Кто-нибудь знает, что я делаю неправильно или что делать, или может указать мне направление, в котором я должен делать?

Ответы [ 4 ]

5 голосов
/ 09 августа 2010

Вы не можете десериализовать класс не POD, переписав существующий экземпляр, как вы, похоже, пытаетесь это сделать - вам нужно дать классу конструктор, который считывает данные из потока и создает новый экземпляр классас ним.

В общих чертах, учитывая что-то вроде этого:

class A {
    A();   
    A( istream & is );    
    void serialise( ostream & os );
    vector <int> v;
};

тогда serialise () запишет длину вектора, за которой следует содержимое вектора.Конструктор считывает длину вектора, изменяет размер вектора, используя длину, а затем считывает содержимое вектора:

void A :: serialise( ostream & os ) {
    size_t vsize = v.size();    
    os.write((char*)&vsize, sizeof(vsize));
    os.write((char*)&v[0], vsize * sizeof(int) );
}

A :: A( istream & is ) {
    size_t vsize;
    is.read((char*)&vsize, sizeof(vsize));
    v.resize( vsize );
    is.read((char*)&v[0], vsize * sizeof(int));
}
2 голосов
/ 09 августа 2010

Я написал бы в сетевом порядке байтов, чтобы гарантировать, что файл может быть записан и прочитан на любой платформе. Итак:

#include <fstream>
#include <iostream>
#include <iomanip>
#include <vector>

#include <arpa/inet.h>

int main(void) {

  std::vector<int32_t> v = std::vector<int32_t>();
  v.push_back(111);
  v.push_back(222);
  v.push_back(333);


  {
    std::ofstream ofs;
    ofs.open("vecdmp.bin", std::ios::out | std::ios::binary);

    uint32_t sz = htonl(v.size());
    ofs.write((const char*)&sz, sizeof(uint32_t));
    for (uint32_t i = 0, end_i = v.size(); i < end_i; ++i) {
      int32_t val = htonl(v[i]);
      ofs.write((const char*)&val, sizeof(int32_t));
    }

    ofs.close();
  }

  {
    std::ifstream ifs;
    ifs.open("vecdmp.bin", std::ios::in | std::ios::binary);

    uint32_t sz = 0;
    ifs.read((char*)&sz, sizeof(uint32_t));
    sz = ntohl(sz);

    for (uint32_t i = 0; i < sz; ++i) {
      int32_t val = 0;
      ifs.read((char*)&val, sizeof(int32_t));
      val = ntohl(val);
      std::cout << i << '=' << val << '\n';
    }
  }

  return 0;
}
2 голосов
/ 09 августа 2010

Вы используете адрес вектора.То, что вам нужно / нужно, это адрес данных, содержащихся в векторе.Написание, например, будет что-то вроде:

size = example.size();
file.write((char *)&size, sizeof(size));
file.write((char *)&example[0], sizeof(example[0] * size));
1 голос
/ 09 августа 2010

Прочтите ответ другого, чтобы узнать, как читать / записывать двоичную структуру.

Я добавляю это, потому что считаю, что ваши мотивы использования двоичного формата ошибочны. Бинарный формат не будет проще, чем ASCII, обычно это наоборот.

У вас есть много вариантов сохранения / чтения данных для долгосрочного использования (ORM, базы данных, структурированные форматы, файлы конфигурации и т. Д.). Плоский двоичный файл обычно является худшим и сложнее в обслуживании, за исключением очень простых структур.

...