将大数据文件嵌入可执行二进制文件

时间:2016-11-02 14:55:26

标签: c++11 cmake initialization clion compile-time

我正在开发一个C ++ 11应用程序,它应该作为单个可执行二进制文件提供。可选地,用户可以提供他们自己的CSV数据文件以供应用程序使用。为简化起见,假设每个元素的格式为key,value\n。我创建了一个结构,如:

typedef struct Data {
    std::string key;
    std::string value;

    Data(std::string key, std::string value) : key(key), value(value) {}
} Data;

默认情况下,应用程序应使用单个头文件中定义的数据。我已经制作了一个简单的Python脚本来解析默认的CSV文件并将其放入头文件中,如:

#ifndef MYPROJECT_DEFAULTDATA
#define MYPROJECT_DEFAULTDATA

#include "../database/DefaultData.h"

namespace defaults {
    std::vector<Data> default_data = {
        Data("SomeKeyA","SomeValueA"),
        Data("SomeKeyB","SomeValueB"),
        Data("SomeKeyC","SomeValueC"),

        /* and on, and on, and on... */

        Data("SomeKeyASFHOIEGEWG","SomeValueASFHOIEGEWG")
    }
}

#endif //MYPROJECT_DEFAULTDATA

唯一的问题是,该文件很大。我说116&0; 087(12M)线很大,将来可能会用更大的文件替换它。当我包含它时,我的IDE正在尝试解析它并更新索引。它减慢了一切,我几乎无法写任何东西。

我正在寻找一种方法:

  1. 阻止我的IDE(CLion)解析它或
  2. 在cmake中进行切换,该文件仅将此文件与发布可执行文件或
  3. 一起使用
  4. 以某种方式将数据直接注入可执行文件

1 个答案:

答案 0 :(得分:3)

由于您的构建过程已包含一个从CSV生成C ++代码的预处理,因此应该很容易。

步骤1:将大部分生成的数据放在.cpp文件中,而不是标题。

第2步:生成代码,使其不使用vectorstring

以下是如何做到这些:

struct Data
{
    string_view key;
    string_view value;
};

您需要string_view或类似类型的实现。虽然它在C ++ 17中被标准化,但它不依赖于C ++ 17的功能。

至于数据结构本身,这是在标题中生成的内容:

namespace defaults {
    extern const std::array<Data, {{GENERATED_ARRAY_COUNT}}> default_data;
}

{{GENERATED_ARRAY_COUNT}}是数组中的项目数。这就是所有生成的标题都应该公开。生成的.cpp文件有点复杂:

static const char ptr[] =
    "SomeKeyA" "SomeValueA"
    "SomeKeyB" "SomeValueB"
    "SomeKeyC" "SomeValueC"
    ...
    "SomeKeyASFHOIEGEWG" "SomeValueASFHOIEGEWG"
;

namespace defaults 
{
  const std::array<Data, {{GENERATED_ARRAY_COUNT}}> default_data =
  {
      {{ptr+{{GENERATED_OFFSET}}, {{GENERATED_SIZE}}}, {ptr+{{GENERATED_OFFSET}}, {{GENERATED_SIZE}}}},
      {{ptr+{{GENERATED_OFFSET}}, {{GENERATED_SIZE}}}, {ptr+{{GENERATED_OFFSET}}, {{GENERATED_SIZE}}}},
      ...
      {{ptr+{{GENERATED_OFFSET}}, {{GENERATED_SIZE}}}, {ptr+{{GENERATED_OFFSET}}, {{GENERATED_SIZE}}}},
  };
}

ptr是一个字符串,它是所有单个字符串的串联。不需要在各个字符串之间放置空格或\0个字符或其他内容。但是,如果确实需要将这些字符串传递给采用以NULL结尾的字符串的API,则必须将它们复制到std :: string中,或者在每个生成的子字符串后使用生成器粘贴\0个字符。

关键是ptr应该是一个巨大的字符数据块。

{{GENERATED_OFFSET}}和{{GENERATED_SIZE}}是表示单个子字符串的巨型字符数据块中的偏移量和大小。

此方法将解决您的两个问题。它在加载时会快得多,因为它执行零动态分配。它将生成的字符串放在.cpp文件中,从而使您的IDE合作。