我正在寻找一种(算法上)优化的方法,以通过某种形式的字节缓冲区读写不同长度的二进制数据。我需要能够从中创建一个byte
数组。理想情况下,此对象可以重用(在单线程环境中)。这些位始终从左到右读取/写入,并且生成的位序列(因此生成的byte
数组)的长度是变化的(结尾可以填充零,这是没有问题的)。我需要能够一次在1到3位之间进行读/写操作,最好是从short
,byte
,int
之类的原始数值中进行读取/写入...但是,我最初并不当开始填充数组时,我知道数组的大小。这取决于要转换的对象。因此,我实际上不能使用ByteBuffer
,它需要分配一个特定的长度(如本问题/答案中的建议:ByteBuffer and Byte Array)。
读取位时,我可以根据最后读取的位来确定下一个块必须多长时间,因此可以读取特定数量的位。创建的字节数组的末尾应填充零,因此字节数组中最左边的位始终是写入的第一位,最右边的位是最后写入的位,或者是最后写入后的最后填充零。填满最后一个字节。
我正在研究一种算法,该算法需要以很高的频率构造-以后读取-二进制数据。我将此数据存储为byte
数组,并根据它们构造String
,因此我可以将它们用作各种映射中的键(我使用具有1:1映射的字符集,因此我不在转换过程中会丢失信息)。由于缺乏更好的主意,我使用BigInteger
作为缓冲区,并通过将BigInteger
转换为byte[]
来构造字节数组。示例代码:
public void writeByteArray() {
// Needs to be 1, so I have a reliable initialization bit, so that if i insert a lot of leading zeros, they are not cut.
BigInteger buffer = BigInteger.ONE;
buffer = buffer.shiftLeft(somethingBitLength);
buffer = buffer.add(BigInteger.valueOf(something));
buffer = buffer.shiftLeft(somethingElseBitLength);
buffer = buffer.add(BigInteger.valueOf(somethingElse));
...
}
这会生成许多对象,这些对象会立即再次从范围中删除,并且不会转义创建它们的方法上下文。 但是我相信编译器无法识别,大多数短暂的BigIntegers
都没有转义,因此在弹出栈后不会立即销毁它们。一旦我的算法运行了几秒钟,我就会运行剧烈的垃圾收集器,这会增加长度。尽管这部分归因于算法通常抛出的大量对象,但GC运行的主要触发因素似乎是这种方法,而第二种方法则以相反的方式读取二进制数据。
public static final ByteBuilder BYTES = new ByteBuilder();
...
public byte[] write() {
BYTES.reset();
BYTES.append(0b0_101, 3); // arguments: (bits, length)
BYTES.append(something, somethingLength);
...
return BYTES.toArray(); // generates the minimum length array to wrap the buffered bits.
}
public void read(byte[] bytes) {
BYTES.load(bytes);
byte bits = BYTES.next(3) // argument: length. expected: right-aligned bits ('0000_0101', if '101' was read)
bits = BYTES.next(somethingLength)
...
}
从理论上讲,我可以编写这样的class
,但是我怀疑这样一个普遍相关的问题已经解决,或者有一些库比我的{{1 }}。