- 浏览: 208450 次
- 性别:
- 来自: 重庆
-
文章分类
最新评论
转自:http://www.cnblogs.com/smark/archive/2012/05/03/2480034.html
在编写网络通讯的时候我们经常需要把一些数据存储到byte[]中然后再发送出去,数值则是我们经常处理的数据成员。发越少的东西意味着使用更少的IO和带宽 ,所以对传输数据进行压缩也是件非常重要的事情。接下来提到的就是一种基于数字存储的方式在大多数情况下可以节省数值存储空间。
Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。比如对于 int32 类型的数字,一般需要 4 个 byte 来表示。但是采用 Varint,对于很小的 int32 类型的数字,则可以用 1 个 byte 来表示。当然凡事都有好的也有不好的一面,采用 Varint 表示法,大的数字则需要 5 个 byte 来表示。从统计的角度来说,一般不会所有的消息中的数字都是大数,因此大多数情况下,采用 Varint 后,可以用更少的字节数来表示数字信息。下面就详细介绍一下 Varint。
Varint 中的每个 byte 的最高位 bit 有特殊的含义,如果该位为 1,表示后续的 byte 也是该数字的一部分,如果该位为 0,则结束。其他的 7 个 bit 都用来表示数字。因此小于 128 的数字都可以用一个 byte 表示。大于 128 的数字,比如 300,会用两个字节来表示:1010 1100 0000 0010
由于负数的高位为1,所以采用这种压缩处理的时候必须负数转成正数,可以通过以下代码实现int to uint的转换
private static int Zag(uint ziggedValue)
{
int value = (int)ziggedValue;
return (-(value & 0x01)) ^ ((value >> 1) & ~( 1<< 31));
}
private static uint Zig(int value)
{
return (uint)((value << 1) ^ (value >> 31));
}
以下操作是对一个uint进行编码处理
private static ArraySegment<byte> WriteUInt32Variant(uint value)
{
byte[] data = new byte[5];
int count = 0;
do
{
data[count] = (byte)((value & 0x7F) | 0x80);
count++;
} while ((value >>= 7) != 0);
data[count - 1] &= 0x7F;
return new ArraySegment<byte>(data, 0, count);
}
data[count] = (byte)((value & 0x7F) | 0x80); 得到头7位的数值, | 0x80是表明后面的byte也是数字的一部分。
while ((value >>= 7) != 0) 右移7位如果不为零的情况下则继续上面的工作。
data[count - 1] &= 0x7F 把最后byte的最高位设置成0;
接下来就是一个uint的解码过程
private static uint ReadUInt32Variant(ArraySegment<byte> data)
{
uint value = data.Array[0];
if ((value & 0x80) == 0) return value;
value &= 0x7F;
uint chunk = data.Array[1];
value |= (chunk & 0x7F) << 7;
if ((chunk & 0x80) == 0) return value;
chunk = data.Array[2];
value |= (chunk & 0x7F) << 14;
if ((chunk & 0x80) == 0) return value;
chunk = data.Array[3];
value |= (chunk & 0x7F) << 21;
if ((chunk & 0x80) == 0) return value;
chunk = data.Array[4]; ;
value |= chunk << 28;
if ((chunk & 0xF0) == 0) return value;
throw new OverflowException("ReadUInt32Variant Error!");
}
(value & 0x80) == 0 表示最高位为0,说明后面的byte已经不是数值组成部分。
(chunk & 0xF0) == 0 chunk只有4位,如果不是则表明这个byte不是数值存储的一部分。
测试一下看下编码效果
ArraySegment<byte> data = WriteUInt32Variant(Zig(0));
Console.WriteLine(data.Count);
data = WriteUInt32Variant(Zig(567));
Console.WriteLine(data.Count);
data = WriteUInt32Variant(Zig(10000));
Console.WriteLine(data.Count);
data = WriteUInt32Variant(Zig(-100000));
Console.WriteLine(data.Count);
分别是1byte,2byte,3byte,3byte
其实有人会有凝问,为什么不根据情况来用int16等来存储,如果一旦用了int16就说明以后需要转int32就是件非常麻烦的事情,双方程序都需要调整。如果采用Varint进行处理就能达到最好扩展效果和带宽利用率.
发表评论
-
C++的原子操作
2012-12-20 17:43 4696在多进程(线程)访问资源时,能够确保所有其他的进程(线程 ... -
匿名namespace的作用以及它与static的区别
2012-12-20 17:24 1863一。匿名namespace的作用 在C语言中,如果我们 ... -
C++类型萃取技术
2012-12-19 15:16 1156Traits技术可以用来获得一个 类型 的相关信息的。 ... -
TypeList
2012-12-19 13:49 1162转自:http://blog.csdn.n ... -
template <unsigned int N>
2012-12-19 11:51 1508详见:http://stackoverflow.com/ ... -
二维指针*(void **)的研究(uC/OS-II案例)
2012-12-19 22:20 3308原文 : http://blog.csdn ... -
多级指针和链表
2012-12-18 22:28 0如果看到一个声明:t ... -
理解*(void**)b
2012-12-18 22:03 0#include <stdio.h> ... -
STL标准库:Allocator能做什么
2012-12-18 20:10 0The Standard Librarian: Wha ... -
三种的allocator实现源代码的对比
2012-12-18 19:55 1352转自:http://blog.csdn.net ... -
结构体内变量相对便宜与list_entry()宏
2012-12-18 17:59 962#define list_entry(ptr, t ... -
声明与函数、函数指针---(*(void (*)( ) )0)( ) 解析
2012-12-18 17:33 1122概述 在很 ... -
c++模板(类型依赖)说明例子
2012-12-18 16:57 1171#include <iostream> # ... -
C++中三种new的用法
2012-12-18 16:44 1843我评价自己的C++水平还未入门的确不够准确,应该是远远未 ... -
C++,永久改变你写异常安全代码的方式(神奇的Loki::ScopeGuard)
2012-12-17 20:19 2527作者:Andrei Alexandrescu and P ... -
C++的make_pair函数
2012-12-17 17:19 3536Pairs C++标准程序库中凡是“必须返回两 ... -
C++的explicit构造函数
2012-12-13 15:59 683按照默认规定,只有一个参数的构造函数也定义了一个隐式转换 ...
相关推荐
而signed-varint库则解决了这个问题,它能够以可变长度的方式存储有符号整数,较小的数值占用较少的字节,较大的数值占用较多的字节,但总体上比固定宽度的整数更节省空间。 signed-varint库的工作原理是基于Google...
1. **Varint**:这是一种无符号整型的压缩方法,它利用了小数值出现概率较高的特性,通过自适应编码来减少存储空间。Varint编码时,每个字节的最高位用作继续标志,其余位用来存储数值的一部分。然而,Varint并不...
在IT领域,压缩编码是一种非常重要的技术,它用于减少数据的存储空间和传输带宽,提高效率。在“Var_Fib_fib2020.com_压缩编码_”这个主题中,我们主要关注两种编码方式:Varint编码和Fibonacci编码。 **Varint编码...
- Varint编码优化了int类型存储,小数值可以用更少的字节表示,减少了空间占用。 - ZigZag编码解决了负数占用更多字节的问题,使得正负数交替表示时能节省空间。 二、差分算法 1. 差分算法的基本思想是只保存数据...
- 数值数据采用VarInt编码。 - 业务数据采用quicklz压缩算法。 - 数据写入采用双循环Buffer机制。 - 重复数据引用写入,减少实际存储的数据量。 #### 九、性能测试结果 根据测试结果,在配备Intel i7 8550U...
这种编码方式对于小数值占用更少的字节,对于大数值,字节长度随着数值大小线性增长。 3. **压缩算法**:虽然描述中提到"对协议内容进行了编码和压缩",但Protobuf本身并不包含内置的压缩功能。然而,开发者可以在...
LevelDB的核心特性包括支持任意字节数组作为键和值、自定义的键值排序规则、简单的API接口、数据快照功能、Snappy压缩以减少存储占用和提高I/O效率,以及对大规模数据集的支持。 在LevelDB中,数据首先存储在内存中...
varint是一种可变长度的整数表示方法,它能够根据实际数值的大小决定使用多少字节来存储。这与UTF-8编码有异曲同工之妙,通过检查字节的最高位来判断编码长度。listpack支持使用1到5个字节来编码元素长度,这使得它...
它的核心编码规则基于Base 128 Varints编码,这是一种压缩整数序列化的方法,能有效节省存储空间,尤其适用于在网络传输或磁盘存储中。 Varints编码的基本原理如下: 1. 每个字节的最高位(msb)作为连续标志,如果...
例如,使用二进制编码(如varint)或基于几何属性的编码,如六角网格编码。这种编码方法可以显著减小数据的大小,同时保持定位精度。 三、空间索引 在大量经纬度数据的场景下,构建空间索引来加速查询至关重要。...
Protobuf 使用了一种称为“变长整数编码”(Varint)的编码方式来压缩整数字段,这种方式将整数编码成一系列字节,使得小数值占用较少的空间。此外,对于字符串和其他消息类型,Protobuf 使用长度前缀编码,以确保...
- **Protocol Buffer**是一种用于数据序列化的高效工具,支持多种编程语言(如Java、C++、Python等),能够实现数据的有效存储和传输。 #### 二、概念与工作原理 1. **概念介绍** - **Protocol Buffer**:一种...
4. **Varint**: 变长整数编码技术,用于节省空间,尤其是在小数值频繁出现的情况下效果显著。 5. **ValueType**: 定义了数据类型的枚举,例如指明是新键值还是覆盖或删除等操作。 6. **SequenceNumber**: 顺序号,...