c++ 读取在 python 中创建的二进制文件中的地图
c++ read map in binary file which created in python
我创建了一个 Python 脚本来创建以下地图(插图):
map<uint32_t, string> tempMap = {{2,"xx"}, {200, "yy"}};
并将其保存为 map.out 文件(二进制文件)。
当我尝试从 C++ 读取二进制文件时,它没有复制映射,为什么?
map<uint32_t, string> tempMap;
ifstream readFile;
std::streamsize length;
readFile.open("somePath\map.out", ios::binary | ios::in);
if (readFile)
{
readFile.ignore( std::numeric_limits<std::streamsize>::max() );
length = readFile.gcount();
readFile.clear(); // Since ignore will have set eof.
readFile.seekg( 0, std::ios_base::beg );
readFile.read((char *)&tempMap,length);
for(auto &it: tempMap)
{
/* cout<<("%u, %s",it.first, it.second.c_str()); ->Prints map*/
}
}
readFile.close();
readFile.clear();
不可能读取原始字节并让它构造一个map
(或大多数容器,就此而言)[1] ;因此,您将不得不编写一些代码来执行正确的 serialization。
如果 stored/loaded 中的数据很简单,如您的示例所示,那么您可以轻松设计一个序列化方案,然后编写代码来加载它。例如,一个简单的明文映射可以通过将每个成员写在换行符之后的文件来建立:
<number>
<string>
...
所以对于你的例子:
std::map<std::uint32_t, std::string> tempMap = {{2,"xx"}, {200, "yy"}};
这可以编码为:
2
xx
200
yy
在这种情况下,反序列化的代码将简单地逐一读取每个值并重建 map
:
// Note: untested
auto loadMap(const std::filesystem::path& path) -> std::map<std::uint32_t, std::string>
{
auto result = std::map<std::uint32_t, std::string>{};
auto file = std::ifstream{path};
while (true) {
auto key = std::uint32_t{};
auto value = std::string{};
if (!(file >> key)) { break; }
if (!std::getline(file, value)) { break; }
result[key] = std::move(value);
}
return result;
}
注意:要实现此功能,您需要 python 程序输出将从 C++ 程序读取的格式。
如果您尝试 read/write 的数据足够复杂,您可以研究不同的序列化交换格式。由于您在 python 和 C++ 之间工作,因此您需要研究支持两者的库。有关建议列表,请参阅 Cross-platform and language (de)serialization
的答案
[1]
您不能仅将整个容器作为字节读取(或写入)并让它工作的原因是因为容器中的数据不是内联存储的。写出原始字节不会自动为您生成类似 2 xx\n200 yy\n
的内容。相反,您将编写指向间接数据结构(例如地图的内部节点对象)的指针的原始地址。
例如,假设的 map
实现可能包含如下节点:
template <typename Key, typename Value>
struct map_node
{
Key key;
Value value;
map_node* left;
map_node* right;
};
(真正的map
实现比这复杂得多,但这是一个简化的表示)
如果 map<Key,Value>
包含一个 map_node<Key,Value>
成员,那么将其写成二进制将写出 key
、value
、left
和 right
-- 后者是指针。对于使用任何类型的间接的任何容器也是如此。地址在写入和读取时会根本不同,因为它们取决于程序在任何给定时间的状态。
你可以写一个简单的 map_node
来测试这个,然后打印出字节看看它产生了什么;指针也将被序列化。从行为上讲,这与您尝试使用 map
并从二进制文件中读取的内容完全相同。请参阅以下包含不同地址的示例。
您可以使用 协议缓冲区 在 python 中序列化您的地图,并且可以在 C++ 中执行反序列化。
协议缓冲区同时支持 Python 和 C++。
我创建了一个 Python 脚本来创建以下地图(插图):
map<uint32_t, string> tempMap = {{2,"xx"}, {200, "yy"}};
并将其保存为 map.out 文件(二进制文件)。 当我尝试从 C++ 读取二进制文件时,它没有复制映射,为什么?
map<uint32_t, string> tempMap;
ifstream readFile;
std::streamsize length;
readFile.open("somePath\map.out", ios::binary | ios::in);
if (readFile)
{
readFile.ignore( std::numeric_limits<std::streamsize>::max() );
length = readFile.gcount();
readFile.clear(); // Since ignore will have set eof.
readFile.seekg( 0, std::ios_base::beg );
readFile.read((char *)&tempMap,length);
for(auto &it: tempMap)
{
/* cout<<("%u, %s",it.first, it.second.c_str()); ->Prints map*/
}
}
readFile.close();
readFile.clear();
不可能读取原始字节并让它构造一个map
(或大多数容器,就此而言)[1] ;因此,您将不得不编写一些代码来执行正确的 serialization。
如果 stored/loaded 中的数据很简单,如您的示例所示,那么您可以轻松设计一个序列化方案,然后编写代码来加载它。例如,一个简单的明文映射可以通过将每个成员写在换行符之后的文件来建立:
<number>
<string>
...
所以对于你的例子:
std::map<std::uint32_t, std::string> tempMap = {{2,"xx"}, {200, "yy"}};
这可以编码为:
2
xx
200
yy
在这种情况下,反序列化的代码将简单地逐一读取每个值并重建 map
:
// Note: untested
auto loadMap(const std::filesystem::path& path) -> std::map<std::uint32_t, std::string>
{
auto result = std::map<std::uint32_t, std::string>{};
auto file = std::ifstream{path};
while (true) {
auto key = std::uint32_t{};
auto value = std::string{};
if (!(file >> key)) { break; }
if (!std::getline(file, value)) { break; }
result[key] = std::move(value);
}
return result;
}
注意:要实现此功能,您需要 python 程序输出将从 C++ 程序读取的格式。
如果您尝试 read/write 的数据足够复杂,您可以研究不同的序列化交换格式。由于您在 python 和 C++ 之间工作,因此您需要研究支持两者的库。有关建议列表,请参阅 Cross-platform and language (de)serialization
的答案[1]
您不能仅将整个容器作为字节读取(或写入)并让它工作的原因是因为容器中的数据不是内联存储的。写出原始字节不会自动为您生成类似 2 xx\n200 yy\n
的内容。相反,您将编写指向间接数据结构(例如地图的内部节点对象)的指针的原始地址。
例如,假设的 map
实现可能包含如下节点:
template <typename Key, typename Value>
struct map_node
{
Key key;
Value value;
map_node* left;
map_node* right;
};
(真正的map
实现比这复杂得多,但这是一个简化的表示)
如果 map<Key,Value>
包含一个 map_node<Key,Value>
成员,那么将其写成二进制将写出 key
、value
、left
和 right
-- 后者是指针。对于使用任何类型的间接的任何容器也是如此。地址在写入和读取时会根本不同,因为它们取决于程序在任何给定时间的状态。
你可以写一个简单的 map_node
来测试这个,然后打印出字节看看它产生了什么;指针也将被序列化。从行为上讲,这与您尝试使用 map
并从二进制文件中读取的内容完全相同。请参阅以下包含不同地址的示例。
您可以使用 协议缓冲区 在 python 中序列化您的地图,并且可以在 C++ 中执行反序列化。
协议缓冲区同时支持 Python 和 C++。