您绝对不应该自动生成对这样的地图进行硬编码的 C++ 代码。有一些库可以将 json 文件直接读入 C++(例如,参见 rapid json),应该使用这些库。代码将编译得更快,读取 20,000 个文件所需的时间大约为几毫秒(而不是编译需要超过 5 分钟)。
如果您想避免在 C++ 代码中添加对 json 解析器的依赖,我建议将 JSON 文件转换为更简单的格式,以便使用 C++ 阅读。
从文件中读取和写入地图的非常非常简单的格式
我们来一张简单的地图:
map<string, map<string, string>> test_map {
{"Hello", {
{"A", "B"},
{"C", "D"}}},
{"World", {
{"Blarg", "glug glug glug"},
{"idek what to put here", "felt cute might delete later"}}}};
我们将使用一种非常简单的格式将其写入文件。字符串将写为<string length> <string text>,映射将写为<map length> <map key-value pairs>。因此,例如,"Hello world" 将写作11 Hello world。对于上面的地图,对应的文件是
2 5 Hello2 1 A1 B1 C1 D5 World2 5 Blarg14 glug glug glug21 idek what to put here28 felt cute might delete later
你有 2,这意味着顶层地图有 2 个元素。后面跟着一个 5,这意味着第一个键中有 5 个字符。接下来是第一个映射的键和值等。
以这种格式将映射写入文件
因为格式很简单,所以做起来也很简单。
namespace output {
using std::map;
using std::string;
void write(FILE* file, string const& str) {
// Write the length of the string, followed by a space
fprintf(file, "%lu ", str.size());
// Write the string itself
fwrite(str.data(), 1, str.size(), file);
}
template<class Key, class Value>
void write(FILE* file, map<Key, Value> const& m) {
// Write the length of the map, followed by a space
fprintf(file, "%lu ", m.size());
for(auto& entry : m) {
// Write the key
write(file, entry.first);
// Write the value
write(file, entry.second);
}
}
}
从文件中读取地图
这也很简单。例如,要读取一个字符串,我们先读取长度,然后再读取所有字符。
namespace input {
using std::map;
using std::string;
void read(FILE* file, size_t& length) {
int result = fscanf(file, "%lu ", &length);
if(result < 0) throw std::logic_error("Couldn't read from file");
}
void read(FILE* file, string& str) {
size_t length; // Read the length
read(file, length);
str.resize(length);
size_t n_read = fread(&str[0], 1, length, file); // Read the characters
if(n_read != length) { // Handle errors
throw std::logic_error("Unable to read entirety of string from file");
}
}
template<class Key, class Value>
void read(FILE* file, map<Key, Value>& text) {
size_t length; // Read the length of the map
read(file, length);
text.clear();
for(size_t i = 0; i < length; i++) {
Key key;
read(file, key); // Read the key
read(file, text[key]); // Read the value
}
}
}
使用此代码
要写地图:
void write_map(string file, map<string, map<string, string>> test_map) {
auto output_file = fopen(file.c_str(), "w");
output::write(output_file, test_map);
fclose(output_file);
}
阅读地图:
map<string, map<string, string>> read_map(string file) {
auto input_file = fopen(file.c_str(), "r");
map<string, map<string, string>> m;
input::read(file, m);
fclose(input_file);
return m;
}
测试这段代码
You can see a live demonstration here
这个主函数会将测试映射写入文件,然后将其读回不同的映射,然后比较两者。
int main() {
using std::map;
using std::string;
map<string, map<string, string>> test_map {
{"Hello", {{"A", "B"}, {"C", "D"}}},
{"World", {{"Blarg", "glug glug glug"}, {"idek what to put here", "felt cute might delete later"}}}
};
{
auto output_file = fopen("example.txt", "w");
output::write(output_file, test_map);
fclose(output_file);
}
map<string, map<string, string>> map_from_file;
{
auto input_file = fopen("example.txt", "r");
try {
input::read(input_file, map_from_file);
} catch(std::logic_error& err) {
std::cerr << "Reading example.txt failed: " << err.what() << '\n';
}
fclose(input_file);
}
std::cout << std::boolalpha << "Maps equivilant? " << (test_map == map_from_file) << '\n';
for(auto pair : map_from_file) {
std::cout << '"' << pair.first << "\" -> {\n";
for(auto kv : pair.second) {
std::cout << " \"" << kv.first << "\" -> \"" << kv.second << '"' << "\n";
}
std::cout << "}\n";
}
}