以二进制形式序列化和反序列化向量

时间:2010-08-09 07:37:38

标签: c++ file-io vector binary

我在尝试将矢量(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();  
}

READ:

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 个答案:

答案 0 :(得分:5)

您不能通过覆盖现有实例来取消序列化非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));
}

答案 1 :(得分:2)

您正在使用向量的地址。您需要/想要的是向量所持有的数据的地址。例如,写作就像是:

size = example.size();
file.write((char *)&size, sizeof(size));
file.write((char *)&example[0], sizeof(example[0] * size));

答案 2 :(得分:2)

我会以网络字节顺序写入,以确保可以在任何平台上写入和读取文件。所以:

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

答案 3 :(得分:1)

阅读对方的答案,看看你应该如何读/写二进制结构。

我添加了这个,因为我相信你使用二进制格式的动机是错误的。二进制格式对于ASCII格式来说并不容易,通常是另一种方式。

您可以选择保存/读取数据以供长期使用(ORM,数据库,结构化格式,配置文件等)。除了非常简单的结构之外,平面二进制文件通常是最差的并且更难维护。