不知看到这篇文章的人,是否也曾饱受c#常见的序列化方式之苦,在数据量较小的情况下,效率上没有什么问题,一旦数据量过大,速度上简直惨不忍睹。在数据量特别大的情况下(之前需要快速保存上百兆的数据,当然,一般可能不会有如此大),文章最后提供的二进制序列化方式会比1,2快几十倍,比3快几倍。
1.object序列化
这是一种比较常见的类序列化方式,只要定义的类以及其包含的所有变量都是可以被序列化的,就可以用这种方式,很方便,写好两个工具方法后可以很方便的在二进制文件和类之间做转换。但是,真的慢,慢的我都想骂街。
///<summary>
/// 序列化
/// </summary>
/// <param name="data">要序列化的对象</param>
/// <returns>返回存放序列化后的数据缓冲区</returns>
public static byte[] Serialize(object data)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream rems = new MemoryStream();
formatter.Serialize(rems, data);
return rems.GetBuffer();
}
/// <summary>
/// 反序列化
/// </summary>
/// <param name="data">数据缓冲区</param>
/// <returns>对象</returns>
public static object Deserialize(byte[] data)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream rems = new MemoryStream(data);
data = null;
return formatter.Deserialize(rems);
}
2.BitConverter.GetBytes()
这个方法可以直接将一些基础类型转化为byte数组。
3.BinaryWirter和BinaryReader
这两个类是c#提供的二进制序列化的读写类,速度与前两个相比有天壤之别,于是,花了点时间看了一下源码(有兴趣可以自己看看源码),恍然大悟,原来还可以这么玩,于是,将它的方法搬运出来,自己写了一个类,也方便针对不同的需求添加和获取数据,我之前由于需要存取Terrain的很多信息,所以加上了一些对一二三维数组的操作。可能是由于c#提供的读写类提供了很多安全性的判断吧,自己写完之后比原生的要快上好几倍。
4.利用位运算和不安全代码来序列化
由于整形可以和byte直接转换,不需要指针,直接用位运算就可以了,但对于浮点型和其他类型来说,就需要做一些取地址等其他操作了。这里不详细解释*((float*)&temp)这一串东西了,看看c++的指针和取地址符,再结合c#的不安全代码就可以了。由于定义了unsafe关键字,项目设置一定要改成 允许不安全代码。
完整的类我上传到了github,通过下面的链接可以获取https://github.com/xdedzl/XFramework,在这个工程里面搜索ProtocolByte即可。
#region 添加获取整数
/// <summary>
/// 将Int32转化成字节数组加入字节流
/// </summary>
/// <param name="num">要转化的Int32</param>
public void AddInt32(int num)
{
bufferList.Add((byte)num);
bufferList.Add((byte)(num >> 8));
bufferList.Add((byte)(num >> 16));
bufferList.Add((byte)(num >> 24));
}
/// <summary>
/// 将字节数组转化成Int32
/// </summary>
public int GetInt32()
{
if (buffer == null)
return 0;
if (buffer.Length < index + 4)
return 0;
return (int)(buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24);
}
#endregion
#region 添加获取浮点数
/// <summary>
/// 将float转化成字节数组加入字节流
/// </summary>
/// <param name="num">要转化的float</param>
public unsafe void AddFloat(float num)
{
uint temp = *(uint*)#
bufferList.Add((byte)temp);
bufferList.Add((byte)(temp >> 8));
bufferList.Add((byte)(temp >> 16));
bufferList.Add((byte)(temp >> 24));
}
/// <summary>
/// 将字节数组转化成float
/// </summary>
public unsafe float GetFloat()
{
if (buffer == null)
return -1;
if (buffer.Length < index + sizeof(float))
return -1;
uint temp = (uint)(buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24);
return *((float*)&temp);
}
#endregion