10

How can I concat two ByteBuffers to one ByteBuffer?

The following doesn't work:

    ByteBuffer bb = ByteBuffer.allocate(100);
    ByteBuffer bb2 = ByteBuffer.allocate(200);
    bb.allocate(200).put(bb2);
    System.out.println(bb.array().length);

The length of bb is still 100.

marcospereira
  • 12,045
  • 3
  • 46
  • 52
mcfly soft
  • 11,289
  • 26
  • 98
  • 202

5 Answers5

12

Something like

bb = ByteBuffer.allocate(300).put(bb).put(bb2);

should do the job: Create a buffer that is large enough to hold the contents of both buffers, and then use the relative put-methods to fill it with the first and the second buffer. (The put method returns the instance that the method was called on, by the way)

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • 7
    **WARNING :** `position` and `limit` will both be set to `capacity` which is probably **not** what you would expect or want if you are going to process the resulting `ByteBuffer` further. You will want to call `.flip()` to be able to process the entire contents of the returned `ByteBuffer` by adding `.flip();` at the end. –  Jun 23 '16 at 17:57
  • Yes, `flip()` or `position(0)` (I personally find the latter more readable) – Marco13 Jun 23 '16 at 19:04
3

We'll be copying all data. Remember that this is why string concatenation is expensive!

public static ByteBuffer concat(final ByteBuffer... buffers) {
    final ByteBuffer combined = ByteBuffer.allocate(Arrays.stream(buffers).mapToInt(Buffer::remaining).sum());
    Arrays.stream(buffers).forEach(b -> combined.put(b.duplicate()));
    return combined;
}
TJR
  • 3,617
  • 8
  • 38
  • 41
  • Seems to work (and is cleaner than other proposed solutions) except you probably want to add before the end: `combined.rewind();` – Jesse Glick Jan 20 '23 at 16:22
  • I agree, it's ambiguous. Should the cursor be at the front or end. Maybe the method name should indicate that. – TJR Jan 22 '23 at 23:22
0

you can use the method here

https://github.com/ata4/ioutils/blob/047e401d73c866317af2e12f7803b3ee43eec80a/src/main/java/info/ata4/io/buffer/ByteBufferUtils.java#L289

and for example:

  ByteBuffer concat() {
int length = 0;
for (ByteBuffer bb : buffers) {
  bb.rewind();
  length += bb.remaining();
}
ByteBuffer bbNew = ByteBuffer.allocateDirect((int) length);

// put all buffers from list
for (ByteBuffer bb : buffers) {
  bb.rewind();
  bbNew.put(bb);

}
bbNew.rewind();
return bbNew;
}
Y00
  • 666
  • 1
  • 7
  • 23
0

Probably because on line3 i.e. bb.allocate(200).put(bb2); ,

bb.allocate(200) is returning a new Byte buffer (See https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#allocate(int) ). That is not actually changing bb itself. So its still the bytebuffer of capacity 100 from line1.

Sid_idk
  • 11
  • 2
-1

Try the following code:

//store both ByteBuffer object as an array
byte[] array1 = ByteBuffer.allocate(100).array();
byte[] array2 = ByteBuffer.allocate(200).array();

//create a ByteBuffer which is big enough
ByteBuffer bigenough = ByteBuffer.allocate(array1.length + array2.length);

//put the two arrays in one ByteBuffer
ByteBuffer after1 = bigenough.put(array1, 0, array1.length);
ByteBuffer result = after1.put(array2, array1.length, array2.length);

//print the length of the combined array.
System.out.println(result.array().length);