2012-07-06 21 views
0

什麼是獲取int的字節表示形式(即byte[]),但僅使用3個字節(而不是4)的一種很好的可讀方式?我正在使用Hadoop/Hbase,它們的Bytes實用程序類具有toBytes函數,但它總是使用4個字節。理想情況下,我還想要一個很好的,可讀的編碼方式,儘可能少的字節,即如果數字適合一個字節,然後只使用一個字節。獲取int的字節表示形式,僅使用3個字節

請注意,我將它存儲在byte[]中,所以我知道數組的長度,因此不需要可變長度編碼。這是關於尋找一個優雅的方式來演員。

+0

字節[0]是LSB還是MSB? [javadoc](http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Bytes.html#toBytes(int))不明確 – 2012-07-07 00:07:14

+0

@RayToal 0是MSB。 – marcog 2012-07-07 00:17:51

+0

您需要確保在使用其他類型的實際更小或更快的(或您優先考慮的)例如你可以用'byte []'來代替'int',但它會更大,更慢和更難使用。 – 2012-07-07 07:36:18

回答

4

一個通用的解決方案是不可能的。

如果可能的話,您可以迭代地應用函數來獲得無限制的數據壓縮。

您的域可能對允許將它們壓縮爲24位的整數有一些限制。如果有這樣的限制,請在問題中解釋它們。

一個常見的可變長度編碼是使用每個字節的7位數據,高位作爲標誌來指示當前字節是最後一個字節。


可以預測與a utility method編碼int所需的字節上Integer數:

int n = 4 - Integer.numberOfLeadingZeros(x)/8; 
byte[] enc = new byte[n]; 
while (n-- > 0) 
    enc[n] = (byte) ((x >>> (n * 8)) & 0xFF); 

注意,這將在小端編碼0作爲空數組和其他值格式爲。這些方面很容易通過一些操作進行修改。

+0

這隻有在您將這些數據與其他字節一起存儲時纔是如此。作爲一個單獨的'byte []',我們知道長度,並且我們知道數組中的所有字節都已設置。 – marcog 2012-07-06 23:58:56

+0

是的,我在談論沒有外部元數據的字節,如UTF-8編碼的字符。如果單獨存儲一個「長度」值,我會期望整體使用更多的空間(4個字節用於「長度」,加上數據本身)。 – erickson 2012-07-07 00:01:53

+0

Java數組存儲大小,沒有選擇。而且Hbase沒有數據表示的知識,所以在它自己的內部表示中,它編碼了開始/結束。 – marcog 2012-07-07 00:05:27

1

如果需要代表整個2^32現有4字節的整數,則需要之間進行選擇:

  • 固定大小的表示,其中使用4個字節總是;或
  • 可變大小表示,對某些數字至少使用5個字節。

看看UTF-8如何編碼Unicode字符,你可能會得到一些見解。 (你使用一些簡短的前綴來描述必須爲該Unicode字符讀取多少個字節,然後讀取那麼多字節並解釋它們)。

+0

我不認爲這是真的在這種情況下。閱讀我對@ erickson的回答的評論。 – marcog 2012-07-06 23:59:32

+0

我不確定我明白你的意思。如果您嘗試使用少於4個字節來表示32位整數,我只能假設您想要節省空間。看起來,從你所說的「一個字節[]」,你有其他類型的結構來隔離一個字節[]。想一想:這個結構會佔用一些空間(即使你不知道它),所以你沒有在32位以內代表2^32個整數。 – 2012-07-07 00:04:00

+0

我正在將數據寫入hbase,並且它不知道正在存儲的數據的結構。所以它必須表示字節的開始/結束或長度。無論我使用3或4字節,情況都是如此。所以寫3個字節應該節省空間。 – marcog 2012-07-07 00:07:58

0

將您int到4 byte列數組,並重復它,如果每一個高位字節是零,那麼從陣列中刪除。

喜歡的東西:

byte[] bytes = toBytes(myInt); 
int neededBytes = 4; 
for (;neededBytes > 1; i--) { 
    if (bytes[neededBytes - 1] != 0) { 
     break; 
    } 
} 

byte[] result = new byte[neededBytes]; 
// then just use array copy to copy first neededBytes to result. 
+0

OP也可能想要處理負數,所以它不僅僅是刪除零的問題。你可能也想刪除-1s。 – 2012-07-07 00:02:12

+0

在這種情況下,值爲正值。 – marcog 2012-07-09 20:57:30

0

你可以像這樣開始:

byte[] Convert(int i) 
{ // warning: untested 
    if (i == 0) 
    return new byte[0]; 
    if (i > 0 && i < 256) 
    return new byte[]{(byte)i}; 
    if (i > 0 && i < 256 * 256) 
    return new byte[]{(byte)i, (byte)(i >> 8)}; 
    if (i > 0 && i < 256 * 256 * 256) 
    return new byte[]{(byte)i, (byte)(i >> 8), (byte)(i >> 16)}; 
    return new byte[]{(byte)i, (byte)(i >> 8), (byte)(i >> 16), (byte)(i >> 24)}; 
} 

你需要決定是否要爲小端或大端。請注意負數以4個字節編碼。

1

嘗試使用ByteBuffer。

int exampleInt = 0x11FFFFFF; 
ByteBuffer buf = ByteBuffer.allocate(Integer.SIZE/Byte.SIZE); 
final byte[] threeByteBuffer = new byte[3]; 
buf.putInt(exampleInt); 
buf.position(1); 
buf.get(threeByteBuffer); 

或者最短的簽署,大端:如果需要,您甚至可以設置小端模式

BigInteger bi = BigInteger.valueOf(exampleInt); 
final byte[] shortestSigned = bi.toByteArray(); 
0

如果我理解正確的,你真的,拼命想節省空間,甚至不惜代價神祕的比特洗牌:任何數組類型都是不必要的豪華,因爲你不能使用少於一個整個字節的長度=尋址空間256,而你知道至多需要4個字節。所以我會保留4位的長度和符號標誌,並將剩下的字節數與其他字節對齊。如果你的MSB小於128,你甚至可以再保存一個字節。我認爲符號標誌對於表示小於4字節的負數的能力也很有用。每次更好(即使是正數)的位數比表示-1的4個字節的開銷更好。

無論如何,直到您對數據集進行了一些統計,有多少整數實際上是可壓縮的,以及壓縮開銷是否值得付出努力之後,這一切都是一筆不小的開支。