【问题标题】:Serializing struct to file, and deserializing it again with string将结构序列化为文件,然后用字符串再次反序列化
【发布时间】:2014-01-24 23:05:01
【问题描述】:

我有以下结构:

struct ArchiveTableEntry
        {
            uint32_t id;
            char filename[MAX_FILENAME_LEN + 1];
            uint32_t filename_crc32;
            uint32_t real_data_size;
            uint32_t block_data_size;

            uint32_t data_crc32;
            char data_md5_checksum[16];

            uint64_t data_offset;
            uint8_t flag;
        };

在序列化之后,我有很好的输出到文件。 从文件加载也可以正常工作。 我使用 memcpy 来执行序列化/反序列化,现在我的问题是:How can I replace char filename[MAX_FILENAME_LEN + 1];通过 std::string,并保持序列化/反序列化工作,并保存 char 浪费的未使用字节。 谢谢!

【问题讨论】:

  • struct 字段可能是内存对齐填充的基础...使用适当的序列化机制来获得尺寸有效的输出(例如 google protobuf)。

标签: c++ string serialization struct deserialization


【解决方案1】:

尽量避免使用 memcpy-ing 指向序列化指针。相反,使用流。你甚至可以创建一个流类来序列化任何类型的数据。接下来,您只需将 > 运算符添加到任何需要序列化的类。

#include <iostream>
#include <fstream>
#include <string>
#include <cstring>

struct ArchiveTableEntry
{
    uint32_t id;
    std::string filename;
    uint32_t filename_crc32;
    uint32_t real_data_size;
    uint32_t block_data_size;

    uint32_t data_crc32;
    char data_md5_checksum[16];

    uint64_t data_offset;
    uint8_t flag;
};

std::ostream& operator << (std::ostream& os, const ArchiveTableEntry entry)
{
    return os << entry.id << entry.filename.size() << entry.filename
              << entry.filename_crc32 << entry.real_data_size << entry.block_data_size
              << entry.data_crc32 << entry.data_md5_checksum << entry.data_offset << entry.flag;
}

std::istream& operator >> (std::istream& os, ArchiveTableEntry& entry)
{
    std::size_t filesize = 0;
    os >> entry.id;
    os >> filesize;
    entry.filename.resize(filesize);
    os.read(&entry.filename[0], filesize);
    os >> entry.filename_crc32 >> entry.real_data_size >> entry.block_data_size >> entry.data_crc32;
    os >> entry.data_md5_checksum >> entry.data_offset >> entry.flag;
    return os;
}



int main()
{
    const char* md5_checksum = "some checksum";

    ArchiveTableEntry data;
    data.id = 1;
    data.filename = "file.txt";
    data.filename_crc32 = 10434235;
    data.real_data_size = 1024;
    data.block_data_size = 256;
    data.data_crc32 = 324225252;
    data.data_md5_checksum = 1;

    std::memset(data.data_md5_checksum, 0, sizeof(data.data_md5_checksum) / sizeof(char));
    strcpy(data.data_md5_checksum, md5_checksum);

    data.data_offset = 512;
    data.flag = 1;

    std::fstream out("C:/Users/School/Desktop/Test.bin", std::ios::out);
    if (out.is_open())
    {
        out << data;
        out.close();
    }

    std::fstream in("C:/Users/School/Desktop/Test.bin", std::ios::in);
    if (in.is_open())
    {
        in >> data;
        in.close();
    }

    std::cout<<data.id<<" "<<data.filename<<" "<<data.filename_crc32<<" "<<data.real_data_size<<" "<<data.block_data_size<<" ";
    std::cout<<data.data_crc32<<" "<<data.data_md5_checksum<<" ";
}

【讨论】:

  • "尽量避免使用 memcpy-ing 指向序列化指针。"是的,如果你讨厌表演。
  • 大声笑.. OP 正在创建一个缓冲区,将所有内容复制到缓冲区并将其写入文件。其次,他不能记忆std::string,这首先是他的问题。他没有将字符串的长度写入文件,然后写入内容。使用流,他不必复制到临时缓冲区然后写入文件。在使用其他标准库类时,这也让他的生活更轻松。
  • 您对 std::string 部分是正确的。但通常您使用可以一次性读取/写入的结构进行序列化/反序列化。这通常比多次小型读/写操作要快。
猜你喜欢
  • 1970-01-01
  • 2012-05-10
  • 2021-01-08
  • 1970-01-01
  • 2014-04-09
  • 2012-08-15
  • 2011-05-19
  • 2020-05-20
  • 1970-01-01
相关资源
最近更新 更多