从 ByteBuffer 中删除前 n 个字节

问题描述 投票:0回答:5

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

java bytebuffer
5个回答
3
投票

你可以尝试这样的事情:

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 类的绝对 getput 方法,并在下一个写入位置设置 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));
}

3
投票

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

尽管文档说:

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

我不确定这个方法是否真的做到了这一点,因为当我调试时,该方法似乎只是做到了

buffer.limit = buffer.capacity


1
投票

您的意思是将所有元素移动到缓冲区的开头吗?像这样:

    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

0
投票

使用紧凑的方法。例如:

    ByteBuffer b = ByteBuffer.allocate(32);
    b.put("hello,world".getBytes());
    b.position(6);      
    b.compact();
    System.out.println(new String(b.array()));

0
投票

您可以使用 ByteBuffer 的内置功能。见下文。

static void shiftByteBuffer(ByteBuffer bb, int numToShift) {
    bb.limit(bb.position());  // Make the buffer "full"
    bb.position(numToShift);  // Set position to numToShift so we only get rid of the first <numToShift> bytes.
    bb.compact();             // Shifts everything and resets indexes
}

您可以使用此方法进行测试,看看它是否有效。

public void shiftByteBuffer_test1() {
    ByteBuffer bb = ByteBuffer.allocate(10).put(new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05});

    assertNotNull(bb);
    assertEquals(10, bb.limit());
    assertEquals(6, bb.position());
    assertEquals((byte)0x00, bb.get(0));
    assertEquals((byte)0x01, bb.get(1));
    assertEquals((byte)0x02, bb.get(2));
    assertEquals((byte)0x03, bb.get(3));
    assertEquals((byte)0x04, bb.get(4));

    PacketEmitter.shiftByteBuffer(bb, 1);

    assertEquals(10, bb.limit());
    assertEquals(5, bb.position());
    assertEquals((byte)0x01, bb.get(0));
    assertEquals((byte)0x02, bb.get(1));
    assertEquals((byte)0x03, bb.get(2));
    assertEquals((byte)0x04, bb.get(3));
}
© www.soinside.com 2019 - 2024. All rights reserved.