【问题标题】:Serialize data is too big序列化数据太大
【发布时间】:2012-10-21 19:23:29
【问题描述】:

我对每个播放器服务器端的数据进行序列化,大小约为 128kb。我序列化了一个 [255,255] 的 bool 数组,这是映射所必需的,我可以使用哪些替代方案,因为我听说 gzip 实际上会增加大小?

我听说过 protobuf-net,但它没有文档记录,互联网上也没有示例。

【问题讨论】:

  • 不,GZipStream 不会增加那个大小。你通过实际尝试来对抗 FUD。
  • @Hans 好吧,它可以做到,这取决于数据看起来有多随机。假设一个好的实现发现数据是随机的,你仍然有帧头的开销。一个糟糕的实现(没有发现它是随机的)几乎可以做任何事情。
  • 你只是添加更多的FUD,它仍然不会让他尝试。

标签: c# serialization protobuf-net


【解决方案1】:

我要做的第一件事是:不要将这些数据存储在 bool[,] 中——这非常低效,而且存储起来真的很痛苦。我会编写一个包装器,将其填充到平面 byte[]

public sealed class BitGrid
{
    public BitGrid() {
        // 255 * 255 = 32 bytes per row, 255 rows
        bytes = new byte[8160];
    }
    public BitGrid(byte[] data)
    {
        if (data == null) throw new ArgumentNullException("data");
        if (data.Length != 8160) throw new ArgumentException("data");
        this.bytes = data;
    }

    readonly byte[] bytes;

    public bool this[byte x, byte y]
    {
        get
        {
            int xByte = x / 8, xBit = x % 8;
            byte val = bytes[(32 * y) + xByte];
            switch (xBit)
            {
                case 0: return (val & 1) != 0;
                case 1: return (val & 2) != 0;
                case 2: return (val & 4) != 0;
                case 3: return (val & 8) != 0;
                case 4: return (val & 16) != 0;
                case 5: return (val & 32) != 0;
                case 6: return (val & 64) != 0;
                case 7: return (val & 128) != 0;
            }
            throw new InvalidOperationException("oops!");
        }
        set
        {
            int xByte = x / 8, xBit = x % 8;
            int offset = (32 * y) + xByte;
            byte val = bytes[offset];
            if (value)
            {
                switch (xBit)
                {
                    case 0: val |= 1; break;
                    case 1: val |= 2; break;
                    case 2: val |= 4; break;
                    case 3: val |= 8; break;
                    case 4: val |= 16; break;
                    case 5: val |= 32; break;
                    case 6: val |= 64; break;
                    case 7: val |= 128; break;
                }
            }
            else
            {
                switch (xBit)
                {
                    case 0: val &= 254; break;
                    case 1: val &= 253; break;
                    case 2: val &= 251; break;
                    case 3: val &= 247; break;
                    case 4: val &= 239; break;
                    case 5: val &= 223; break;
                    case 6: val &= 191; break;
                    case 7: val &= 127; break;
                }
            }

            bytes[offset] = val;
        }
    }
    public byte[] ToArray()
    {
        return (byte[])bytes.Clone();
    }
}

然后序列化它,就是:

byte[] data = grid.ToArray();
// store "data"

反序列化,它只是:

byte[] data = ...
grid = new BitGrid(data);

您可以使用File.ReadAllBytes / File.WriteAllBytes 方法将byte[] 保存/加载到磁盘或从磁盘加载,或者如果您有其他数据要存储,那么任何标准序列化程序都可以使用byte[]。此数据将始终为 8160 字节 - 略低于 8k。

【讨论】:

    【解决方案2】:

    如果您将布尔值表示为位并将序列化为二进制,则只有大约 8 KB。

    如果你需要是文本,使用 base64 序列化二进制文件,这将使它大约 12 KB。

    将二维数组展平为一维数组,并从中生成BitArray

    例子:

    bool[] bools = { true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true };
    
    BitArray bits = new BitArray(bools);
    byte[] bytes = new byte[3];
    bits.CopyTo(bytes, 0);
    
    Console.WriteLine(BitConverter.ToString(bytes));
    Console.WriteLine(Convert.ToBase64String(bytes));
    

    输出:

    FF-FF-0F
    //8P
    

    【讨论】:

    • 我将如何“展平”阵列?我将如何从 base64 重新创建它?这么多问题...
    • @Max0999:简单地循环遍历数组中的项目并将它们复制到一个新数组以展平它。使用 Convert.FromBase64String 从 base64 取回字节。使用new BitArray(bytes) 再次创建BitArray,使用CopyTo 方法将数据复制到bool 数组中。
    • 255 * 255 = 65025 位,即 8129 字节。你从哪里得到 1.3k?
    • @MarcGravell:你是对的,当然。我的 calc fu 今天似乎很弱。也许我在除以 8 时双击了……更正了。 :)
    • @Max0999: 嗯...那你做错了...base64字符串本身应该小于12 kB...
    【解决方案3】:

    您可以使用(一维)BitArray 进行序列化。这会将位打包成字节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-05
      • 1970-01-01
      • 2017-10-25
      • 1970-01-01
      • 2018-07-09
      • 1970-01-01
      • 2016-12-06
      相关资源
      最近更新 更多