0

什么是获取 an 的字节表示(即 a byte[]int但仅使用 3 个字节(而不是 4 个)的好、易读的方法?我正在使用 Hadoop/Hbase,它们的Bytes实用程序类有一个toBytes函数,但总是使用 4 个字节。

理想情况下,我还想要一种好的、可读的编码方式,尽可能少地编码,即如果数字适合一个字节,则只使用一个。

请注意,我将它存储在 a 中byte[],因此我知道数组的长度,因此不需要可变长度编码。这是关于找到一种优雅的方式来进行演员阵容。

4

6 回答 6

3

对此的通用解决方案是不可能的。

如果可能的话,您可以迭代地应用该函数来获得无限的数据压缩。

您的域可能对允许将它们压缩为 24 位的整数有一些限制。如果有这样的限制,请在问题中解释。

一种常见的可变大小编码是使用每个字节的 7 位作为数据,高位作为标志来指示当前字节何时是最后一个字节。


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 编码为空数组,并将其他值编码为little-endian格式。这些方面很容易通过更多的操作进行修改。

于 2012-07-06T23:56:05.737 回答
1

尝试使用字节缓冲区。如果需要,您甚至可以设置小端模式:

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);

或者最短的签名,Big Endian:

BigInteger bi = BigInteger.valueOf(exampleInt);
final byte[] shortestSigned = bi.toByteArray();
于 2012-07-07T00:43:17.107 回答
1

如果您需要表示整个 2^32 个现有的 4 字节整数,则需要在以下选项中进行选择:

  • 固定大小的表示,总是使用 4 个字节;或者
  • 可变大小表示,对于某些数字至少使用 5 个字节。

看看 UTF-8 如何对 Unicode 字符进行编码,您可能会有所了解。(您使用一些短前缀来描述必须为该 unicode 字符读取多少字节,然后您读取那么多字节并解释它们)。

于 2012-07-06T23:56:46.023 回答
0

如果我理解正确,你真的非常想节省空间,即使以奥术位改组为代价:任何数组类型都是不必要的奢侈品,因为你不能使用少于一个完整字节的长度 = 寻址空间 256,而你知道在大多数将需要 4 个。所以我会为长度和符号标志保留 4 位,并将其余的与该字节数对齐。如果您的 MSB 小于 128,您甚至可以再节省一个字节。我认为符号标志对于用小于 4 个字节表示负数的能力也很有用。最好每次都有这个位(即使是正数)而不是 4 个字节的开销来表示 -1。

无论如何,在您对数据集进行一些统计、实际可压缩的整数数量以及压缩开销是否值得付出努力之前,这一切都是虚无缥缈的。

于 2012-07-07T12:40:21.263 回答
0

将您转换int为 4 bytes 数组,并对其进行迭代,如果每个高位字节都为零,则将其从数组中删除。

就像是:

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.
于 2012-07-06T23:58:11.333 回答
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 个字节编码。

于 2012-07-07T00:25:32.323 回答