我想在Java中使用long值,并将其转换为字节数组。
但是,我希望小值的表示很小,所以如果值小于127,那么它只需要一个字节。
编码和解码算法应该非常有效。
我确定已经完成但我找不到任何示例代码,任何人都有任何指针?
答案 0 :(得分:4)
您可以使用停止位编码,例如
public static void writeLong(OutputStream out, long value) throws IOException {
while(value < 0 || value > 127) {
out.write((byte) (0x80 | (value & 0x7F)));
value = value >>> 7;
}
out.write((byte) value);
}
public static long readLong(InputStream in) throws IOException {
int shift = 0;
long b;
long value = 0;
while((b = in.read()) >= 0) {
value += (b & 0x7f) << shift;
shift += 7;
if ((b & 0x80) == 0) return value;
}
throw new EOFException();
}
这是一种快速压缩形式,但所有压缩都需要付出代价。 (但是,如果您的带宽有限,那么传输速度可能会更快并且值得花费)
BTW:值0到127使用一个byte
。您也可以对short
和int
值使用相同的例程。
编辑:在此之后你仍然可以使用通用压缩,它可以小于不使用它。
public static void main(String... args) throws IOException {
long[] sequence = new long[1024];
Random rand = new Random(1);
for (int i = 0; i < sequence.length; i+=2) {
sequence[i] = (long) Math.pow(2, rand.nextDouble() * rand.nextDouble() * 61);
// some pattern.
sequence[i+1] = sequence[i] / 2;
}
testDeflator(sequence);
testStopBit(sequence);
testStopBitDeflator(sequence);
}
private static void testDeflator(long[] sequence) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(new DeflaterOutputStream(baos));
for (long l : sequence)
dos.writeLong(l);
dos.close();
System.out.println("Deflator used " + baos.toByteArray().length);
}
private static void testStopBit(long[] sequence) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (long l : sequence)
writeLong(baos, l);
baos.close();
System.out.println("Stop bit used " + baos.toByteArray().length);
}
private static void testStopBitDeflator(long[] sequence) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(new DeflaterOutputStream(baos));
for (long l : sequence)
writeLong(dos, l);
dos.close();
System.out.println("Stop bit & Deflator used " + baos.toByteArray().length);
}
public static void writeLong(OutputStream out, long value) throws IOException {
while (value < 0 || value > 127) {
out.write((byte) (0x80 | (value & 0x7F)));
value = value >>> 7;
}
out.write((byte) value);
}
打印
Deflator used 3492
Stop bit used 2724
Stop bit & Deflator used 2615
最有效的方法在很大程度上取决于您发送的数据。例如如果您的数据是真正随机的,那么您使用的任何压缩技术都只会使数据更大。
Deflator是GZip输出的精简版本(减去标题和CRC32)
答案 1 :(得分:2)
简单地使用GZipOutputStream
- 像GZip这样的熵编码基本上完全按照你描述的方式进行,只是一般。
修改强> 只是为了确定:你是否意识到对于小数字只使用1个字节的可变长度编码对于大多数大数字必须使用超过8个字节?除非您知道自己的数量远小于大数字,否则最终可能会增加数据的整体大小。而GZIP适应您的实际数据集,并且可以压缩以不同方式偏斜的数据集。
答案 2 :(得分:1)
请参阅C#中的Read7BitEncodedInt。 (这是相同的概念。)
答案 3 :(得分:0)
如果要存储具有不同长度的long
值,那么您将需要一个分隔符,否则您无法确定哪个字节属于哪个长值...并且分隔符将添加额外的字节数据......
如果您正在寻找一个快速库来存储长值(每个64Bit),我建议colt。 快。
答案 4 :(得分:0)
(我可能会向某些人陈述这些显而易见的......但是这里有。)
如果您要在某些外部序列化中减小long
个值,请继续。
但是,如果您尝试在Java程序中保存内存,则可能会浪费您的时间。 Java中byte[]
的最小表示是2或3个32位字。这是一个长度为零的字节数组。对于任何大于零的数组长度,添加一些32位字的倍数。然后,您必须允许至少1个32位字来保存对byte[]
对象的引用。
如果你添加它,至少需要4个单词才能代表long
以外的任何0L
作为byte[]
。
如果您要在单个long
中表示多个byte[]
值,那么您将获得任何保存的唯一情况。在你可能收支平衡之前,你需要至少3 long
个值,即使这样,如果你的价值平均来说太大,你也会失败。