Remove first n bytes from a ByteBuffer

11,897

Solution 1

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

Solution 2

I think the method you are looking for is the ByteBuffer's compact() method

Even though the documentation says:

"The bytes between the buffer's current position and its limit, if any, are copied to the beginning of the buffer. That is, the byte at index p = position() is copied to index zero, the byte at index p + 1 is copied to index one, and so forth until the byte at index limit() - 1 is copied to index n = limit() - 1 - p. The buffer's position is then set to n+1 and its limit is set to its capacity."

I am not sure that this method realy does that, because when I debug it seems like the method just does buffer.limit = buffer.capacity.

Solution 3

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
Share:
11,897
Blaker
Author by

Blaker

Updated on June 13, 2022

Comments

  • Blaker
    Blaker about 2 years

    How can I remove the first n number of bytes from a ByteBuffer without changing or lowering the capacity? The result should be that the 0th byte is the n+1 byte. Is there a better data type in Java to do this type of action?

  • Blaker
    Blaker almost 11 years
    The removeBytesFromStart function works perfectly! Thank you for adding the unit tests too!
  • Blaker
    Blaker almost 11 years
    Thanks andreih! I marked A4L's answer as the 'correct' due to the brevity of the solution. Thanks again!
  • Randall Whitman
    Randall Whitman over 9 years
    This answer avoids double write of bytes from n to limit-n, for the case of n < limit/2.