8

I have a byte[] bytes from a ByteBuffer which contains a packet. I want to put the packet in a String.

Currently I have the following

    byte[] bytes = packet.array();
    System.out.println("Packet String:" + new String(bytes));

But then I end up with the following output

Packet String:E����<Ҧ@��@�.
03-22 04:30:28.187   9296-10152/willem.com.vpn I/System.out﹕ ����J}�j���k�:����������9�������
03-22 04:30:28.197   9296-10152/willem.com.vpn I/System.out﹕ ��&�4��������ddrarpa��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

I've tried it with encoding like this

System.out.println("Packet String:" + new String(bytes, Charset.forName("UTF-8")));

But that isn't the right charset. Can anybody tell me what is?

2
  • Nobody can tell you what the correct Charset for your own file is. Only you, or the software that wrote it, can yield that. Commented Mar 22, 2015 at 8:15
  • The following reference on JAVA NIO ByteBuffer Basic Usage explains why you are reading garbaje. Commented Sep 13, 2016 at 12:44

4 Answers 4

12

You need to use the buffer's position and limit to determine the number of bytes to read.

// ...populate the buffer...
buffer.flip(); // flip the buffer for reading
byte[] bytes = new byte[buffer.remaining()]; // create a byte array the length of the number of bytes written to the buffer
buffer.get(bytes); // read the bytes that were written
String packet = new String(bytes);

In my opinion you shouldn't really be using the backing array() at all; it's bad practice. Direct byte buffers (created by ByteBuffer.allocateDirect() won't have a backing array and will throw an exception when you try to call ByteBuffer.array(). Because of this, for portability you should try to stick to the standard buffer get and put methods. Of course, if you really want to use the array you can use ByteBuffer.hasArray() to check if the buffer has a backing array.

Sign up to request clarification or add additional context in comments.

6 Comments

Then i get a java.nio.BufferUnderflowException and the string still doesn't make sense
It sounds like you may need to call flip first. When the buffer is written, before you read it again you often need to call flip to reset the position and limit. flip will set the position to 0 and the limit to the current position, thus making remaining equivalent to the number of bytes that were written into the buffer.
Where do I need to call it?
Normally you should call flip after any writing to the buffer. flip is meant to be used to switch between writing and reading from the buffer. When bytes are written, the buffer's position is advanced. In order to then read from it you need to flip the buffer to start back at the beginning for reading. The ByteBuffer API is a bit confusing and can take a while to understand.
I would say you need to call flip() just before any reading from the buffer, and call compact() immediately afterwards. It's easiest to maintain buffers as always ready for writing to (and reading into), and only have them in the flipped state for as short a time as possible.
|
1

The answer talking about setting range from position to limit is not correct in a general case. When the buffer has been partially consumed, or is referring to a part of an array (you can ByteBuffer.wrap an array at a given offset, not necessarily from the beginning), we have to account for that in our calculations. This is the general solution that works for buffers in all cases (does not cover encoding):

if (myByteBuffer.hasArray()) {
    return new String(myByteBuffer.array(),
        myByteBuffer.arrayOffset() + myByteBuffer.position(),
        myByteBuffer.remaining());
} else {
    final byte[] b = new byte[myByteBuffer.remaining()];
    myByteBuffer.duplicate().get(b);
    return new String(b);
}

For the concerns related to encoding, see Andy Thomas' answer.

1 Comment

This is the solution that worked for me. Thank you.
0

You're ignoring the limit of the buffer. You should flip() the buffer, then call

new String(buffer.array(), 0, buffer.position())

Then reset it.

But you should really be using a Charset decoder to yield a CharBuffer for this. At least you should specify a character set to the String constructor.

5 Comments

You create it, call CharsetDecoder.decode(ByteBuffer) to produce a CharBuffer, then turn that directly into a String.
But I don't know what charset to use, how do I find out?
There's not a great way to know the character set of an arbitrary byte array. You sort of need to know that thing ahead of time. There are a few libraries like Apache Tika which provide guesstimation of character sets, but as with any format guessing it's an imperfect science.
should specify encoding, but more seriously buffer.limit() is an offset, not the length. the constructor wants teh length of bytes to use.
You should flip() the buffer, then call this will reset the position to zero. Therefore, new String(buffer.array(), 0, buffer.position()) won't work.
-1

ByteBuffer data = ...

new String(data.array() , "UTF-8");

1 Comment

array() will return the backing array of ByteBuffer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.