【问题标题】:position of bits in binary stream二进制流中位的位置
【发布时间】:2020-10-03 10:24:30
【问题描述】:

我编写了一个用于增强/序列化的 C++ 程序。我已经在二进制流上写入和读取项目。但问题是,我想改变一些项目的位置。

例子:

void write(...){
 if(!file_streamer_) {
 ...
 a_ = new boost::archive::binary_oarchive(*file_streamer_);
 }
 for(...){
     (*oa_) & obj[i] ;}
 // calculating the some properties of objects (long x long y long z)
 // and add them to stream
 (*oa_) & x;
 (*oa_) & y;
 (*oa_) & z;

 }
          // read


        void read(...){
       ia_=new boost::archive::binary_iarchive(*file_streamer_in_);
       std::streampos archive_offset = file_streamer_in_->tellg();
       std::streampos stream_end = file_streamer_in_->seekg(0, std::ios_base::end).tellg();
       file_streamer_in_->seekg(archive_offset);
        while (file_streamer_in_->tellg() < stream_end){
        //read objects 
          ...
    } 
    }

那是我的二进制流:

obj_1 obj_2 obj_3 obj_4 obj_5 x y z

但我想这样改变:

 x y z obj_1 obj_2 obj_3 obj_4 obj_5 

如何将最后一部分添加到流的开头? 提前致谢。

【问题讨论】:

  • 将行 (*oa_) &amp; x; (*oa_) &amp; y; (*oa_) &amp; z; 放在 for 循环之前有什么问题?如果您想先流式传输这三个,则先传输这三个。
  • 我可能无法解释,但你可以相信我,我不能先添加它们。
  • 不,我不敢相信。 XY problem 的可能性更大。
  • “我可能无法解释” 那么这就是你的确切问题:你正在做一些事情,但你不知道为什么要这样做。听听你的小疑问。在继续之前,请确保您清除了所有此类疑问。想象有人在半夜叫醒你。如果你不能解释它,你就不应该这样做。你不能做任何这些,也不能为每一件小事提供详细的推理。您在不理解的情况下“凭感觉编程”。结局总是很糟糕。没有其他方式可以结束。而且你现在的情况比较典型。

标签: c++ serialization boost


【解决方案1】:

我不认为二进制存档是您最初认为的那样。

docs > 的存在表明档案和 C++ i/o 流之间存在关系。档案不是 C++ i/o 流

文档的基本原理中甚至有一整节:

Archives are not streams

归档类不是从流派生的,即使它们有 类似的语法规则。

  • 归档类不是流的种类,尽管它们是根据流实现的。这种区别在[5]中得到解决 项目编号 41。
  • 我们不希望用户插入/提取数据 直接进入/来自流。这可能会造成损坏 档案。如果档案来自流,则有可能 不小心这样做了。所以归档类只定义操作 是安全且必要的。
  • 使用流来实现库中包含的归档类只是方便 - 不是必需的。图书馆 用户可能很想定义自己的存档格式 完全使用流。

特别注意项目符号 2,(我的粗体字)。这与我在这里看到的代码完全不一致:

void read(...){
   ia_=new boost::archive::binary_iarchive(*file_streamer_in_);
   std::streampos archive_offset = file_streamer_in_->tellg();
   std::streampos stream_end = file_streamer_in_->seekg(0, std::ios_base::end).tellg();
   file_streamer_in_->seekg(archive_offset);
    while (file_streamer_in_->tellg() < stream_end){
    //read objects 

此代码以各种可能的方式违反了该合同。


版本控制

要将文件中的格式更改为某些新布局,请定义不同的版本。见Class Versioning

这样你就可以做一个版本 1:

struct MyType {
    int a, b;
    template <typename Ar> void serialize(Ar& ar, unsigned v) {
        switch (v) {
            case 0: ar & a & b; return;
            case 1:
            default: ar & b & a; return;
        }
    }
};

BOOST_CLASS_VERSION(MyType, 0)

int main() {
    std::vector<MyType> many(10, MyType{5,7});
    std::ofstream ofs("v0.dat", std::ios::binary);
    boost::archive::binary_oarchive oa(ofs);
    oa << many;
}

然后当您决定要更改订单或ab

struct MyType {
    int a, b;
    template <typename Ar> void serialize(Ar& ar, unsigned v) {
        switch (v) {
            case 0: ar & a & b; return;
            case 1:
            default: ar & b & a; return;
        }
    }
};

BOOST_CLASS_VERSION(MyType, 1)

int main() {
    std::vector<MyType> many;
    {
        std::ifstream ifs("v0.dat", std::ios::binary);
        boost::archive::binary_iarchive ia(ifs);
        ia >> many;
    }

    {
        std::ofstream ofs("v1.dat", std::ios::binary);
        boost::archive::binary_oarchive oa(ofs);
        oa << many;
    }
}

您仍然可以正确阅读旧格式。

还有什么……最坏的情况

如果你搞砸了怎么办?使用我的水晶球,您可能已经反向实现了矩阵序列化,现在您无法读取存档,即使在版本 0 中也是如此,因为您不知道一开始有多少元素?

这个问题无法解决(在一般情况下):您不可能知道元素的框架,因为二进制数据流没有任何结构信息。只是字节。

只有通过查看十六进制转储,您才能弄清楚什么是什么。例如。这是上一个示例中的v0.dat

对比v1.dat

你发现的一切都是猜测。原则上,明智的做法是得出您搞砸并丢失了数据的结论。

【讨论】:

    猜你喜欢
    • 2017-06-06
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 1970-01-01
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    • 2012-08-11
    相关资源
    最近更新 更多