我很难理解序列化是什么和做什么的.
让我简化我的问题.我有一个struct info在我的c/c ++程序中,我可以将这些struct数据存储到一个文件中save.bin或通过套接字发送到另一台计算机.
struct info {
std::string name;
int age;
};
void write_to_file()
{
info a = {"Steve", 10};
ofstream ofs("save.bin", ofstream::binary);
ofs.write((char *) &a, sizeof(a)); // am I doing it right?
ofs.close();
}
void write_to_sock()
{
// I don't know about socket api, but I assume write **a** to socket is similar to file, isn't it?
}
Run Code Online (Sandbox Code Playgroud)
write_to_file将简单地将struct info对象保存a到磁盘,使这些数据持久,对吧?把它写到socket上几乎是一样的吧?
在上面的代码中,我不认为我使用了数据序列化,但数据a仍然是持久的save.bin,对吧?
题
那么序列化有什么意义呢?我需要它吗?如果是,我应该如何使用它?
我一直认为任何类型的文件.txt/.csv/.exe/...都是01内存中的一些,这意味着它们自然具有二进制表示,所以我们不能简单地通过套接字直接发送这些文件吗?
代码示例非常受欢迎.
但是无论如何数据a在save.bin中都是持久的,对吧?
没有!你的结构包含一个std::string.确切的实现(以及使用强制转换获得的二进制数据char*不是由标准定义的,但实际的字符串数据总是会在类框架之外的某处重新分配,堆分配,因此您无法轻松保存这些数据通过正确完成序列化,字符串数据被写入到类的其余部分也会结束的位置,因此您可以从文件中读取它.这就是您需要序列化的内容.
怎么做:你必须以某种方式编码字符串,最简单的方法是首先写它的长度,然后是字符串本身.在读回文件时,首先读回长度,然后将该字节数读入新的字符串对象.
我一直认为任何类型的文件,.txt/.csv/.exe/...,都是内存中的01位
是的,但问题是它没有普遍定义哪个位代表数据结构的哪个部分.特别是,有小端和大端架构,它们将这些位"反过来"存储起来.如果你天真地读出一个用不匹配架构编写的文件,你显然会得到垃圾.
只写下二进制内存中的图像是一种序列化的形式,对于琐碎的情况它是有效的.但是一般来说,你需要解决一些只是倾倒内存而不考虑的问题:
如果数据包含任何指针当然你不能只是稍后转储一个加载,因为一旦程序终止并重新启动,指针所指向的内存地址就没有任何意义.许多对象具有"隐藏"指针...例如有没有办法来转储std::vector内存和以后正确装入... sizeof上std::vector显然不包括所包含的元素的大小,因此包含任何结构std::vector不能只是把并重新加载.这同样适用于std::string所有其他std容器.
C和C++结构和类不是根据它们在内存中占用的字节来定义的,而不是可移植的.这意味着不同的编译器,不同的编译器版本或甚至相同的版本但具有不同的编译选项可能会生成内存中的结构布局不相同的代码.
如果你需要序列化只是在同一个程序中保存和重新加载数据,那么它不应该长寿,那么确实可以使用内存转储.然而,只要考虑通过转储结构来保存数百万个文档,现在新的编译器版本(您被迫使用,因为它是新操作系统版本唯一支持的)具有不同的布局,您无法再加载这些文档.
除了同系统可移植性问题之外,还要注意即使只有一个整数,也可以在不同的系统上具有不同的内存表示.它可能更大或更小; 它可能有不同的字节顺序.仅使用内存转储意味着另一个系统无法加载保存的内容.甚至不是一个整数.
如果您保存的数据具有较长的使用寿命,那么随着程序的发展,您很可能会更改结构,例如,您将添加新字段,您将删除未使用的字段,您将更改一般结构(例如,更改矢量到链表).
如果你的格式只是当前数据结构的内存图像,那么以后很难能够将一个color字段添加到一个polygon对象中并且让程序可以加载旧文档,假设默认颜色值是在以前的版本.
即使编写转换程序也很困难,因为您将拥有能够加载旧文档和能够保存新文档的新代码的旧代码,但是您不能只是"合并"这两个并获得一个加载旧程序并保存新程序的程序(即程序源代码将有一个polygon结构但具有不同的字段,现在是什么?).
| 归档时间: |
|
| 查看次数: |
1299 次 |
| 最近记录: |