【问题标题】:Serializing a map<fs::path, fs::path>?序列化地图<fs::path, fs::path>?
【发布时间】:2021-07-21 07:40:56
【问题描述】:

我正在使用谷物库将我的类序列化为文件,但在使用 std::map 时遇到了问题 - 特别是使用 std::filesystem::path 的地图。

假设我有一个仅包含 map&lt;fs::path, fs::path&gt;Object 类,以及谷物所需的序列化函数:

struct Object
{
    map<fs::path, fs::path> _map;

    template<class Archive>
    void serialize(Archive & archive)
    {
        archive(_map);
    }

    friend ostream& operator<<(ostream& outs, const Object c)
    {
        for (auto const &pair: c._map)
            std::cout << "{" << pair.first << ": " << pair.second << "}\n";
        return outs;
    }
};

在我的主要功能中,我有:

int main()
{
    // create Object
    cout << "Creating object..." << endl;
    Object o;
    fs::path a = "bye.txt";
    fs::path b = "hello.txt";
    o._map[a] = b;
    o._map[b] = a;
    cout << "Object created: " << endl;
    cout << o;

    // serialize
    cout << "Serializing object...." << endl;
    stringstream ss;
    cereal::BinaryOutputArchive oarchive(ss);
    oarchive(o);
    cout << "Object serialized." << endl;

    // write to file
    cout << "Writing serialized object to file...." << endl;
    ofstream file("serialized_object");
    file << ss.str();
    file.close();
    cout << "Object written to file." << endl;

    // read from file
    cout << "Reading from file..." << endl;
    stringstream ss2;
    fs::path ins = "serialized_object";
    ifstream file_stream(ins, ios::binary);
    ss2 << file_stream.rdbuf();
    cereal::BinaryInputArchive iarchive(ss2);
    Object out;
    iarchive(out);
    cout << "Object read from file." << endl;
    cout << out;
}

在我的输出中,当它从序列化文件中读取时,我看到了错误:

Creating object...
Object created:
{"bye.txt": "hello.txt"}
{"hello.txt": "bye.txt"}
Serializing object....
Object serialized.
Writing serialized object to file....
Object written to file.
Reading from file...
terminate called after throwing an instance of 'cereal::Exception'
  what():  Failed to read 2573 bytes from input stream! Read 28

我的包括:

#include <iostream>
#include <filesystem>
#include <fstream>
#include <string.h>
#include <map>
#include "cereal/types/map.hpp"
#include "cereal/archives/binary.hpp"
#include "cereal/types/string.hpp"

为了能够序列化fs::path,我在开头包含了以下代码:

namespace std
{
  namespace filesystem
  {
    template<class Archive>
    void CEREAL_LOAD_MINIMAL_FUNCTION_NAME(const Archive&, path& out, const string& in)
    {
        out = in;
    }

    template<class Archive>
    string CEREAL_SAVE_MINIMAL_FUNCTION_NAME(const Archive& ar, const path& p)
    {
      return p.string();
    }
  }
}

我确定我遗漏了一些明显的东西,因为这是我第一次使用麦片。有没有人知道我为什么会遇到这个问题?

【问题讨论】:

  • 也许问题是你不使用ios::binary 代替ofstream

标签: c++ serialization filesystems stdmap cereal


【解决方案1】:

根据谷物文档,在使用 BinaryArchive 时必须始终使用 ios::binary 标志。以下是他们文档中this 页面的具体部分:

当使用二进制存档和文件流 (std::fstream) 时,请记住在构造流时指定二进制标志 (std::ios::binary)。这可以防止流将您的数据解释为 ASCII 字符并更改它们。

另一个问题是基于 Cereal 如何保证序列化已完成。根据下面的link,在尝试读取存档之前,输出存档对象应该超出范围(调用析构函数)。他们使用RAII 方法,就像here 中提到的ifstreamofstream

您可以通过允许 Cereal 库在内部执行写入和读取来大大简化您的代码。这是您的主要功能的修改版本:

int main()
{
    // create Object
    cout << "Creating object..." << endl;
    Object o;
    fs::path a = "bye.txt";
    fs::path b = "hello.txt";
    o._map[a] = b;
    o._map[b] = a;
    cout << "Object created: " << endl;
    cout << o;

    
    cout << "Serializing object...." << endl;
    // scope boundary (a function call would be cleaner)
    {
        ofstream ofstm("serialized_object", ios::binary);
        cereal::BinaryOutputArchive oarchive(ofstm);
        // serialize
        oarchive(o);
    }
    cout << "Object serialized and written." << endl;

    // deserialize the object by reading from the archive
    Object out;

    // scope boundary (a function would be cleaner)
    {
        ifstream istm("serialized_object", ios::binary);
        cereal::BinaryInputArchive iarchive(istm);
        //deserialize
        iarchive(out);
    }
    cout << "Object read from file." << endl;
    cout << out;
}

我希望这会有所帮助。请在使用前对此进行全面测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    • 2019-12-26
    • 2018-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多