日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
談?wù)剶?shù)值壓縮存儲(chǔ)方法Varint

在編寫網(wǎng)絡(luò)通訊的時(shí)候我們經(jīng)常需要把一些數(shù)據(jù)存儲(chǔ)到byte[]中然后再發(fā)送出去,數(shù)值則是我們經(jīng)常處理的數(shù)據(jù)成員。發(fā)越少的東西意味著使用更少的IO和帶寬 ,所以對(duì)傳輸數(shù)據(jù)進(jìn)行壓縮也是件非常重要的事情。接下來提到的就是一種基于數(shù)字存儲(chǔ)的方式在大多數(shù)情況下可以節(jié)省數(shù)值存儲(chǔ)空間。

Varint 是一種緊湊的表示數(shù)字的方法。它用一個(gè)或多個(gè)字節(jié)來表示一個(gè)數(shù)字,值越小的數(shù)字使用越少的字節(jié)數(shù)。這能減少用來表示數(shù)字的字節(jié)數(shù)。比如對(duì)于 int32 類型的數(shù)字,一般需要 4 個(gè) byte 來表示。但是采用 Varint,對(duì)于很小的 int32 類型的數(shù)字,則可以用 1 個(gè) byte 來表示。當(dāng)然凡事都有好的也有不好的一面,采用 Varint 表示法,大的數(shù)字則需要 5 個(gè) byte 來表示。從統(tǒng)計(jì)的角度來說,一般不會(huì)所有的消息中的數(shù)字都是大數(shù),因此大多數(shù)情況下,采用 Varint 后,可以用更少的字節(jié)數(shù)來表示數(shù)字信息。下面就詳細(xì)介紹一下 Varint。

Varint 中的每個(gè) byte 的最高位 bit 有特殊的含義,如果該位為 1,表示后續(xù)的 byte 也是該數(shù)字的一部分,如果該位為 0,則結(jié)束。其他的 7 個(gè) bit 都用來表示數(shù)字。因此小于 128 的數(shù)字都可以用一個(gè) byte 表示。大于 128 的數(shù)字,比如 300,會(huì)用兩個(gè)字節(jié)來表示:1010 1100 0000 0010

由于負(fù)數(shù)的高位為1,所以采用這種壓縮處理的時(shí)候必須負(fù)數(shù)轉(zhuǎn)成正數(shù),可以通過以下代碼實(shí)現(xiàn)int to uint的轉(zhuǎn)換

 
 
 
 
  1. private static int Zag(uint ziggedValue)   
  2. {   
  3. int value = (int)ziggedValue;   
  4. return (-(value & 0x01)) ^ ((value >> 1) & ~( 1<< 31));   
  5. }   
  6. private static uint Zig(int value)   
  7. {   
  8. return (uint)((value << 1) ^ (value >> 31));    

以下操作是對(duì)一個(gè)uint進(jìn)行編碼處理

 
 
 
 
  1. private static ArraySegment WriteUInt32Variant(uint value)   
  2. {   
  3. byte[] data = new byte[5];   
  4. int count = 0;   
  5. do 
  6. {   
  7. data[count] = (byte)((value & 0x7F) | 0x80);   
  8. count++;   
  9. } while ((value >>= 7) != 0);   
  10. data[count - 1] &= 0x7F;   
  11. return new ArraySegment(data, 0, count);   

data[count] = (byte)((value & 0x7F) | 0x80); 得到頭7位的數(shù)值, | 0x80是表明后面的byte也是數(shù)字的一部分。

while ((value >>= 7) != 0) 右移7位如果不為零的情況下則繼續(xù)上面的工作。

data[count - 1] &= 0x7F 把最后byte的最高位設(shè)置成0;

接下來就是一個(gè)uint的解碼過程

 
 
 
 
  1. private static uint ReadUInt32Variant(ArraySegment data)   
  2. {   
  3. uint value = data.Array[0];   
  4. if ((value & 0x80) == 0) return value;   
  5. value &= 0x7F;   
  6. uint chunk = data.Array[1];   
  7. value |= (chunk & 0x7F) << 7;   
  8. if ((chunk & 0x80) == 0) return value;   
  9. chunk = data.Array[2];   
  10. value |= (chunk & 0x7F) << 14;   
  11. if ((chunk & 0x80) == 0) return value;   
  12. chunk = data.Array[3];   
  13. value |= (chunk & 0x7F) << 21;   
  14. if ((chunk & 0x80) == 0) return value;   
  15. chunk = data.Array[4]; ;   
  16. value |= chunk << 28;   
  17. if ((chunk & 0xF0) == 0) return value;   
  18. throw new OverflowException("ReadUInt32Variant Error!");   

(value & 0x80) == 0 表示最高位為0,說明后面的byte已經(jīng)不是數(shù)值組成部分。

(chunk & 0xF0) == 0 chunk只有4位,如果不是則表明這個(gè)byte不是數(shù)值存儲(chǔ)的一部分。

測(cè)試一下看下編碼效果

 
 
 
 
  1. ArraySegment data = WriteUInt32Variant(Zig(0));   
  2. Console.WriteLine(data.Count);   
  3. data = WriteUInt32Variant(Zig(567));   
  4. Console.WriteLine(data.Count);   
  5. data = WriteUInt32Variant(Zig(10000));   
  6. Console.WriteLine(data.Count);   
  7. data = WriteUInt32Variant(Zig(-100000));   
  8. Console.WriteLine(data.Count); 

分別是1byte,2byte,3byte,3byte

其實(shí)有人會(huì)有凝問,為什么不根據(jù)情況來用int16等來存儲(chǔ),如果一旦用了int16就說明以后需要轉(zhuǎn)int32就是件非常麻煩的事情,雙方程序都需要調(diào)整。如果采用Varint進(jìn)行處理就能達(dá)到最好擴(kuò)展效果和帶寬利用率.

原文鏈接:http://www.cnblogs.com/smark/archive/2012/05/03/2480034.html


當(dāng)前標(biāo)題:談?wù)剶?shù)值壓縮存儲(chǔ)方法Varint
URL鏈接:http://m.5511xx.com/article/djjogej.html