将大数据文件嵌入可执行二进制文件
Embedding big data file into executable binary
我正在开发一个 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'087 (12M) 行大,将来可能会被更大的文件替换。当我包含它时,我的 IDE 正在尝试解析它并更新索引。它让一切都变慢,以至于我几乎无法写任何东西。
我正在寻找一种方法:
- 阻止我的 IDE (CLion) 解析它或
- 在 cmake 中进行切换,仅将此文件用于发布可执行文件或
- 以某种方式将数据直接注入可执行文件
由于您的构建过程已经包含一个 pre-process,它从 CSV 生成 C++ 代码,这应该很容易。
第 1 步:将大部分生成的数据放在 .cpp 文件中,而不是 header。
第 2 步:生成您的代码,使其不使用 vector
或 string
。
操作方法如下:
struct Data
{
string_view key;
string_view value;
};
您将需要 string_view
或类似类型的实现。虽然它已在 C++17 中标准化,但它不依赖于 C++17 功能。
至于数据结构本身,这是在 header:
中生成的
namespace defaults {
extern const std::array<Data, {{GENERATED_ARRAY_COUNT}}> default_data;
}
{{GENERATED_ARRAY_COUNT}} 是数组中的项目数。这就是生成的 header 应该公开的所有内容。生成的.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
是一个字符串,它是所有单独字符串的串联。无需在各个字符串之间放置空格或 [=17=]
字符或其他任何内容。但是,如果您确实需要将这些字符串传递给采用 NULL-terminated 字符串的 API,您要么必须将它们复制到 std::string 中,要么让生成器在每次生成后粘贴 [=17=]
个字符sub-string.
重点是 ptr
应该是一个巨大的字符数据块。
{{GENERATED_OFFSET}} 和 {{GENERATED_SIZE}} 是表示单个子字符串的巨大字符数据块内的偏移量和大小。
这个方法可以解决你的两个问题。它在加载时会快得多,因为它执行零动态分配。并将生成的字符串放入 .cpp 文件中,从而使您的 IDE 配合。
我正在开发一个 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'087 (12M) 行大,将来可能会被更大的文件替换。当我包含它时,我的 IDE 正在尝试解析它并更新索引。它让一切都变慢,以至于我几乎无法写任何东西。
我正在寻找一种方法:
- 阻止我的 IDE (CLion) 解析它或
- 在 cmake 中进行切换,仅将此文件用于发布可执行文件或
- 以某种方式将数据直接注入可执行文件
由于您的构建过程已经包含一个 pre-process,它从 CSV 生成 C++ 代码,这应该很容易。
第 1 步:将大部分生成的数据放在 .cpp 文件中,而不是 header。
第 2 步:生成您的代码,使其不使用 vector
或 string
。
操作方法如下:
struct Data
{
string_view key;
string_view value;
};
您将需要 string_view
或类似类型的实现。虽然它已在 C++17 中标准化,但它不依赖于 C++17 功能。
至于数据结构本身,这是在 header:
中生成的namespace defaults {
extern const std::array<Data, {{GENERATED_ARRAY_COUNT}}> default_data;
}
{{GENERATED_ARRAY_COUNT}} 是数组中的项目数。这就是生成的 header 应该公开的所有内容。生成的.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
是一个字符串,它是所有单独字符串的串联。无需在各个字符串之间放置空格或 [=17=]
字符或其他任何内容。但是,如果您确实需要将这些字符串传递给采用 NULL-terminated 字符串的 API,您要么必须将它们复制到 std::string 中,要么让生成器在每次生成后粘贴 [=17=]
个字符sub-string.
重点是 ptr
应该是一个巨大的字符数据块。
{{GENERATED_OFFSET}} 和 {{GENERATED_SIZE}} 是表示单个子字符串的巨大字符数据块内的偏移量和大小。
这个方法可以解决你的两个问题。它在加载时会快得多,因为它执行零动态分配。并将生成的字符串放入 .cpp 文件中,从而使您的 IDE 配合。