【问题标题】:How to save stl container in disk?如何将stl容器保存在磁盘中?
【发布时间】:2021-03-13 15:08:20
【问题描述】:

我有一个stl容器,可以保存很多数据。

例如,定义是:

std::unordered_map<std::string, std::vector<int32_t> > m;  // there are 10 million data in this container

我想要的是将它保存在一个文件中,然后下次我可以读取这个文件以快速恢复它。

我认为是正常的方式,例如:

write(&m, sizeof(m))

不起作用,因为它只保存指针。

那么,我怎样才能将它保存在文件中并通过读取文件来恢复它?

【问题讨论】:

  • c++ 没有开箱即用的序列化。你要么需要自己做,要么使用图书馆。
  • @Evg 很好,但是安装 boost 可能会添加外部库,我可能需要一种独立的方式来做到这一点
  • 那么唯一的选择就是手工、递归、逐个元素地完成。
  • @Evg s/递归/迭代/

标签: c++ serialization stl


【解决方案1】:

选择文件格式,例如一个简单的列表,遍历你的容器并编写每个元素:

for (const auto &el : m) {
    file << el.first << '\n' << el.second.size() << '\n';
    for (const auto &vecEl : el.second) {
        file << vecEl << '\n';
    }
}

然后你就可以读取文件了

std::string first;
std::size_t count;
while (std::getline(file, first) && file >> count) {
    std::vector<int32_t> v(count);
    for (auto &vecEl : v) {
        file >> vecEl;
    }
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    m[first] = v;
}

这只是一个草图。您可能必须添加错误检查。

【讨论】:

  • 感谢jabaa,这是一个好方法,但我认为它可能并不快。保存为二进制格式,然后读出来可能是个好方法,我正在阅读以查找是否可以
  • @nick:作为一般提示 - 随心所欲 - 但当你甚至不知道如何自己做某事时,你应该从你容易做的事情开始,看看它是否运行良好,然后仅在证明需要时才考虑更快的替代方案。
【解决方案2】:

鉴于您不热衷于使用 boost,最低努力最低可重用性选项类似于:

// some support macros for easy error detection/handling...

#define FATAL(MSG) \
    do { \
         std::cerr << "FATAL ERROR at line " << __LINE__ << ":\n" \
             "    " << MSG << '\n'; \
         exit(EXIT_FAILURE); \
    } while (false)

#define ASSERT(X, MSG) \
     do { \
         if (X) break; \
         FATAL("ASSERT(" #X ") FAILED; " << MSG); \
     } while (false)

// output your container to disk...

if (std::ofstream out{filename}) {
    for (auto& [key, value] : m) {
        out << key.size() << ' ';
        out.write(key.data(), key.size();
        out << ' ' << value.size();
        for (auto& i : values)
            out << ' ' << i;
        out >> '\n';
    }
    ASSERT(out, "failed while writing to " << filename);
}
else
    FATAL("failed to create " << filename);

这只是创建一个文件,其中包含如下行:

13 A 13 char str 5 1 2 3 4 5

前导 13 表示您在解析字符串之前就知道字符串中有多少个字符,这样就省去了我们想出一些转义和终止符约定的麻烦,或者没有的风险(例如,假设字符串没有嵌入换行符通常是有风险的)。第一个“5”表示数组长度,只需要加快加载速度,因为它可以让您预先预留足够的内存,这可能比使用.push_back 和在加载数组期间必须使用resize 更快。

读取文件则变为:

if (std::ifstream in{filename}) {
    size_t len;
    while (in >> len) {
        std::string key;
        key.resize(len);
        ASSERT(in.read(key.data(), len));
        ASSERT(in >> len);
        std::vector<int32_t> v;
        v.reserve(len);
        while (len--) {
            ASSERT(in >> num);
            v.push_back(num);
        }
    }
    ASSERT(out.eof(), "failed to parse string size");
    m[std::move(key)] = std::move(v);
}
else
    FATAL("failed to open " << filename);

我没有测试过这个,所以根据需要使用/测试/调试....

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-14
    • 1970-01-01
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 2017-11-17
    • 2018-06-16
    相关资源
    最近更新 更多