【发布时间】:2013-08-03 10:36:59
【问题描述】:
如何在不改变或降低容量的情况下从 ByteBuffer 中删除前 n 个字节?结果应该是第 0 个字节是 n+1 字节。 Java 中是否有更好的数据类型来执行此类操作?
【问题讨论】:
-
您要将第一个
n字节中的每一个设置为零,还是跳过第一个n字节?
标签: java bytebuffer
如何在不改变或降低容量的情况下从 ByteBuffer 中删除前 n 个字节?结果应该是第 0 个字节是 n+1 字节。 Java 中是否有更好的数据类型来执行此类操作?
【问题讨论】:
n 字节中的每一个设置为零,还是跳过第一个n 字节?
标签: java bytebuffer
你可以试试这样的:
public void removeBytesFromStart(ByteBuffer bf, int n) {
int index = 0;
for(int i = n; i < bf.position(); i++) {
bf.put(index++, bf.get(i));
bf.put(i, (byte)0);
}
bf.position(index);
}
或者是这样的:
public void removeBytesFromStart2(ByteBuffer bf, int n) {
int index = 0;
for(int i = n; i < bf.limit(); i++) {
bf.put(index++, bf.get(i));
bf.put(i, (byte)0);
}
bf.position(bf.position()-n);
}
这使用ByteBuffer 类的绝对get 和put 方法,并将position 设置在下一个写入位置。
请注意,绝对 put 方法是可选的,这意味着扩展抽象类 ByteBuffer 的类可能不会为其提供实现,例如它可能会抛出 ReadOnlyBufferException。
您是选择循环到position 还是循环到limit 取决于您如何使用缓冲区,例如,如果您手动设置position,您可能希望使用循环到limit。如果你不这样做,那么循环到position 就足够了,而且效率更高。
这里有一些测试:
@Test
public void removeBytesFromStart() {
ByteBuffer bf = ByteBuffer.allocate(16);
int expectedCapacity = bf.capacity();
bf.put("abcdefg".getBytes());
ByteBuffer expected = ByteBuffer.allocate(16);
expected.put("defg".getBytes());
removeBytesFromStart(bf, 3);
Assert.assertEquals(expectedCapacity, bf.capacity());
Assert.assertEquals(0, bf.compareTo(expected));
}
@Test
public void removeBytesFromStartInt() {
ByteBuffer bf = ByteBuffer.allocate(16);
int expectedCapacity = bf.capacity();
bf.putInt(1);
bf.putInt(2);
bf.putInt(3);
bf.putInt(4);
ByteBuffer expected = ByteBuffer.allocate(16);
expected.putInt(2);
expected.putInt(3);
expected.putInt(4);
removeBytesFromStart2(bf, 4);
Assert.assertEquals(expectedCapacity, bf.capacity());
Assert.assertEquals(0, bf.compareTo(expected));
}
【讨论】:
removeBytesFromStart 函数完美运行!感谢您也添加单元测试!
我想你要找的方法是the ByteBuffer's compact() method
即使文档说:
"缓冲区的当前位置和它的限制之间的字节,如果有的话,被复制到缓冲区的开头。也就是说,索引 p = position() 处的字节被复制到索引零,字节索引 p + 1 处的字节被复制到索引 1,依此类推,直到索引 limit() - 1 处的字节被复制到索引 n = limit() - 1 - p。然后将缓冲区的位置设置为 n+1 及其限制设置为其容量。”
我不确定这个方法真的能做到这一点,因为当我调试时,它似乎只是在做buffer.limit = buffer.capacity。
【讨论】:
您的意思是将所有元素移到缓冲区的开头吗?像这样:
int n = 4;
//allocate a buffer of capacity 10
ByteBuffer b = ByteBuffer.allocate(10);
// add data to buffer
for (int i = 0; i < b.limit(); i++) {
b.put((byte) i);
}
// print buffer
for (int i = 0; i < b.limit(); i++) {
System.out.print(b.get(i) + " ");
}
//shift left the elements from the buffer
//add zeros to the end
for (int i = n; i < b.limit() + n; i++) {
if (i < b.limit()) {
b.put(i - n, b.get(i));
} else {
b.put(i - n, (byte) 0);
}
}
//print buffer again
System.out.println();
for (int i = 0; i < b.limit(); i++) {
System.out.print(b.get(i) + " ");
}
对于 n=4,它将打印:
0 1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 0 0 0 0
【讨论】:
n到limit-n的字节重复写入,对于n < limit/2的情况。
为此使用紧凑的方法。例如:
ByteBuffer b = ByteBuffer.allocate(32);
b.put("hello,world".getBytes());
b.position(6);
b.compact();
System.out.println(new String(b.array()));
【讨论】: