【问题标题】:Serialize and deserialize vector in binary以二进制序列化和反序列化向量
【发布时间】:2010-08-09 07:37:38
【问题描述】:

我在尝试将向量 (std::vector) 序列化为二进制格式然后正确反序列化它并能够读取数据时遇到问题。这是我第一次使用二进制格式(我使用的是 ASCII,但现在太难使用了),所以我从一个整数向量开始。

每当我读回数据时,向量总是有正确的长度,但数据要么是 0,要么是未定义的,要么是随机的。

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

写:

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();
}

有谁知道我做错了什么或该做什么或能够指出我需要做的方向吗?

【问题讨论】:

  • 欢迎来到 SO。要格式化代码块,请将整个代码缩进 4 个空格。
  • 谢谢,格式让我抓狂。我一直在与其他人讨论我的问题,似乎我需要对向量中的每个元素以及向量的大小进行多次写入调用。
  • 您可能想花一些时间阅读stackoverflow.com/editing-help

标签: c++ file-io vector binary


【解决方案1】:

您不能像您试图做的那样通过覆盖现有实例来反序列化非 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));
}

【讨论】:

  • @Neil:哎呀,我在错误的条目上添加了 ASCII 格式的部分。希望你不会介意。我将删除我自己的答案。
  • @Neil:更准确地说,您可以只序列化(或 memcopy)普通类。
  • @kriss 添加了关于非 POD 的注释以回答。
  • @Neil:我什至会说它是“非 POD 和微不足道的”,因为您甚至不能以这种方式管理所有 POD 结构(不允许动态结构或指针)。
  • 这几乎就是我的做法。保存长度,然后保存内容。读取长度,然后读取内容。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      我添加这个是因为我认为您使用二进制格式的动机是错误的。二进制格式不会比 ASCII 格式更容易,通常情况正好相反。

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

      【讨论】:

      • 我使用 ASCII 的方式很简单,但不是非常模块化或可扩展的。我以前没有做过二进制文件,所以我想我会试一试,谢谢你的评论。
      猜你喜欢
      • 2014-01-04
      • 1970-01-01
      • 2011-06-08
      • 1970-01-01
      • 2016-12-31
      • 1970-01-01
      • 2010-11-08
      • 2021-12-03
      • 2016-09-15
      相关资源
      最近更新 更多