如何读取和写入非固定长度的结构到二进制文件c++

Posted

技术标签:

【中文标题】如何读取和写入非固定长度的结构到二进制文件c++【英文标题】:how to read and write non-fixed-length structs to biniary file c++ 【发布时间】:2021-10-22 23:27:53 【问题描述】:

我有结构向量:

typedef struct

    uint64_t id = 0;
    std::string name;
    std::vector<uint64_t> data;
 entry;

我想写入文件:

FILE *testFile = nullptr;
testFile = fopen("test.b", "wb");

但是普通的读/写方法

fwrite(vector.data(), sizeof vector[0], vector.size(), testFile);
fread(vector.data(), sizeof(entry), numberOfEntries, testFile);

不起作用,因为条目的大小可能因内容而异

std::string name;
std::vector<uint64_t> data;

所以我想要有关如何从文件中读取/写入这些数据的方法和指针。

【问题讨论】:

逐个元素地编写它,并包含有关向量有多少条目以及字符串有多少字符/字节的信息。尝试保存结构/类的内存表示通常效果不佳,并且在涉及非基本数据类型时肯定不会奏效。 进一步研究的关键词:序列化。 【参考方案1】:

在处理非固定大小的数据时,以某种方式跟踪大小非常重要。您可以简单地指定固定大小元素的数量或整个结构的字节大小,并在读取结构时计算所需的值。我赞成第一个,尽管它有时会使调试变得更加困难。

这是一个如何制作灵活的序列化系统的示例。

struct my_data

   int a;
   char c;
   std::vector<other_data> data;


template<class T>
void serialize(const T& v, std::vector<std::byte>& out)

   static_assert(false, "Unsupported type");


template<class T>
requires std::is_trivially_copy_constructible_v<T>
void serialize(const T& v, std::vector<std::byte>& out)

   out.resize(std::size(out) + sizeof(T));
   std::memcpy(std::data(out) + std::size(out) - sizeof(T), std::bit_cast<std::byte*>(&v), sizeof(T));


template<class T>
void serialize<std::vector<T>>(const std::vector<T>& v, std::vector<std::byte>& out)

   serialize<size_t>(std::size(v), out); // add size
   for(const auto& e : v)
      serialize<T>(v, out);


template<>
void serialize<my_data>(const my_data& v, std::vector<std::byte>& out)

   serialize(v.a, out);
   serialize(v.c, out);
   serialize(v.data, out);


// And likewise you would do for deserialize

int main()

   std::vector<std::byte> data;
   my_data a;
   serialize(a, data);

   // write vector of bytes to file

这是一项乏味的工作,并且已经有一些库可以为您完成这项工作,例如 Google's Flatbuffers、Google's Protobuf 或单个标头 BinaryLove3。其中一些使用聚合类型开箱即用(意味着所有成员变量都是公共的)。下面是 BinaryLove3 的示例。

#include <iostream>
#include <vector>
#include <string>
#include <cstdint>
#include <string>
#include <list>

#include "BinaryLove3.hpp"

struct foo

    uint32_t v0 = 3;
    uint32_t v1 = 2;
    float_t v2 = 2.5f;
    char v3 = 'c';
    struct
    
        std::vector<int> vec_of_trivial =  1, 2, 3 ;
        std::vector<std::string> vec_of_nontrivial =  "I am a Fox!", "In a big Box!" ;
        std::string str = "Foxes can fly!";
        std::list<int> non_random_access_container =  3, 4, 5 ;
     non_trivial;
    struct
    
        uint32_t v0 = 1;
        uint32_t v1 = 2;
     trivial;
;

auto main() -> int32_t

    foo out =  4, 5, 6.7f, 'd', 5, 4, 3, 2, "cc", "dd", "Fly me to the moon..." , 7, 8, 9, 3, 4 ;
    auto data = BinaryLove3::serialize(bobux);
    
    foo in;
    BinaryLove3::deserialize(data, in);
    return int32_t(0);

【讨论】:

以上是关于如何读取和写入非固定长度的结构到二进制文件c++的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 中读取文件时动态分配内存给结构

C++怎么读取或者写入到局域网共享的文件内容?

使用回车行终止符读取/写入固定长度的文本记录

将结构写入二进制文件 C++ 时遇到问题

为啥C语言输出文件内容乱码

在二进制文件中读取和写入字符串c ++