2

如何在不更改或降低容量的情况下从 ByteBuffer 中删除前n个字节?结果应该是第0个字节是n+1个字节。Java 中是否有更好的数据类型来执行此类操作?

4

4 回答 4

3

You could try something like this:

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

Or something like this:

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

This uses the absolute get and put method of the ByteBuffer class and sets the position at next write position.

Note that the absolute put method is optional, which means that a class that extends the abstract class ByteBuffer may not provide an implementation for it, for example it might throw a ReadOnlyBufferException.

Whether you choose to loop till position or till limit depends on how you use the buffer, for example if you manually set the position you might want to use loop till limit. If you do not then looping till position is enough and more efficient.

Here is some testings:

@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));
}
于 2013-08-03T14:18:55.980 回答
3

我认为您正在寻找的方法是ByteBuffer 的 compact() 方法

即使文档说:

“缓冲区的当前位置与其限制之间的字节(如果有)被复制到缓冲区的开头。也就是说,索引 p = position() 处的字节被复制到索引零,索引 p + 1 处的字节是复制到索引 1,依此类推,直到索引 limit() - 1 处的字节被复制到索引 n = limit() - 1 - p。然后将缓冲区的位置设置为 n+1,并将其限制设置为其容量。”

我不确定这个方法真的能做到这一点,因为当我调试时,它看起来就像这个方法一样buffer.limit = buffer.capacity

于 2015-06-25T10:09:38.357 回答
1

Do you mean to shift all the element to the begining of the buffer? Like this:

    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) + " ");
    }

For n=4 it will print:

0 1 2 3 4 5 6 7 8 9 
4 5 6 7 8 9 0 0 0 0
于 2013-08-03T14:17:25.870 回答
0

为此使用紧凑的方法。例如:

    ByteBuffer b = ByteBuffer.allocate(32);
    b.put("hello,world".getBytes());
    b.position(6);      
    b.compact();
    System.out.println(new String(b.array()));
于 2017-11-09T20:14:46.013 回答