使用二进制文件存储,可以在不压缩数据的前提下尽量的节省空间。
情景:在使用Unity制作游戏的时候,需要存储一个非常大的信息。大概是千万级别(8192×8192)的byte数组。然后计算内存大概是8192*8192/1024/1024 = 64 MB大小。
使用Json存储
后来我用json存下了文件,到处之后。发现内存600MB,这样游戏里肯定是没有办法用的。于是看了.json文件。到处之后多了很多逗号、空格,所以占用了很多的内存空间。于是使用:
public static string ToJson(object obj, bool prettyPrint);
去掉了所有的空格,这样导出之后的内存是128MB,毕竟json的 逗号 是去不掉的。。至此放弃Json文件保存信息。
使用二进制保存
放弃Json之后,想了想目测二进制可以没有 逗号 直接存储为文件。这样的话起码可以把内存控制在64MB。结果还可以接受。于是开始设想怎么自定义一个方法存储我的结构(Struct),要不要自定义存储和读取方式之类。想了想没什么头绪,于是面向Google编程试试,发现自定义的结构可以直接格式化输出到硬盘。代码如下:
//引用库
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
//示例方法
void Save (string customPath)
{
FileStream fs = new FileStream(customPath,FileMode.Create);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(fs, customPath);
fs.Flush();
fs.Close();
}
这样就可以直接将自定义结构存储为二进制文件了,读取的时候也很方便,使用下列代码即可。
void Load (string customPath)
{
FileStream fs = new FileStream(customPath,FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Deserialize(fs);
fs.Close();
}
这样就可以实现存储和读取二进制文件的功能了。
二进制保存+数据压缩
OK上边说到了直接使用C#的BinaryFormatter()方法进行序列化。但是内存只是达到了一开始的预计内存64MB。那么还有没有办法能再节省一些内存呢。于是我研究了我要存储的数据,发现数据大小只有从0-4几个范围,其实只需要3个bit就可以存下来。完全可以把1个byte的8bit拆分为两个存储数据。
下面写具体的做法:
我们采用4bit存一个数据的话,可以先把要存的第一个数据存到一个byte里然后做左移运算,存到高位。要存的第二个数据不用动。然后通过两个byte 或 运算,获得要存储的byte数据。之后取的话,取高位数据时右移,取低位数据时和0000 1111(10进制下15)做与运算,即可取到低位数据。
过程如下图:
C#实现:
//取
public static byte UnpackByte(byte oriByte,bool isLow)
{
if (isLow)
{
return (byte)(oriByte & 15);
}
else
{
return (byte)(oriByte>> 4);
}
}
//存
public static byte SaveByte(byte data,bool isLow)
{
if (isLow)
{
return (byte)((data & 15)<<4);
}
else
{
//低位
byte fbit1 = (byte)(data & 15);
byte fbit2 = (byte)(data & 240);
return (byte)(fbit2 | fbit1);
}
}